Foundry Test : ERC721 SOL (Postmortem)
Tags: blockchain, solidity, foundry, gasreport
Published: 2023-06-18 19:46:45

A smart contract development toolchain called Foundry offers resources for testing smart contracts. 
Forge, a testing framework for Solidity smart contracts, is one of Foundry's key components. 
Writing unit tests, integration tests, and fuzz tests for smart contracts is possible using Forge.

Forge is better than truffle and hardhat for testing and deploying smart contract on local and main chains .

> Let's start the testing of ERC721 NFT smart contract and write the unit tests for ERC721 methods . 

In the End we will also get the gas report by forge that's the best part of this foundry tool .

ERC721 Smart Contract you will get from solidity-by-example : `https://solidity-by-example.org/app/erc721/` . We will test this contract methods .

let list the functions that would need to be test :- 

- | approve                       
- | balanceOf 
- | burn 
- | getApproved
- | isApprovedForAll 
- | mint
- | ownerOf 
- | safeTransferFrom 
- | setApprovalForAll

`Test minting function by Bob Address :-` 

```
 function testMintingERC721() public{
        erc721.mint(bob,0);
        address _owner = erc721.ownerOf(0);
        uint iud = erc721.balanceOf(bob);
        assertEq(iud,1);
        assertEq(bob,_owner);
    }
```

`Test Owner function by Bob Address :-`

```
function testOwnerOfToken() public{
        erc721.mint(bob,0);
        address _owner = erc721.ownerOf(0);
        assertEq(bob,_owner);
    }
```
`Test Transfer function by Bob Address :-`

```
function testTransferFrom() public {
        erc721.mint(bob,0);
        vm.startPrank(bob);
        erc721.safeTransferFrom(bob,alice,0);
        address _owner = erc721.ownerOf(0);
        assertEq(alice,_owner);
        uint iud = erc721.balanceOf(alice);
        assertEq(iud,1);
    }   
```
`Test GetBalance function by Bob Address :-`

```
function testGetBalance() public {
        erc721.mint(bob,0);
        erc721.mint(bob,1);
        erc721.mint(bob,2);
        erc721.mint(bob,3);
        erc721.mint(bob,4);
        erc721.mint(bob,5);
        uint bal = erc721.balanceOf(bob);
        assertEq(bal,6);
    }
```
`Test only owner can burn function by Bob Address :-`

```
 function testOnlyOwnerBurn() public {
        erc721.mint(bob,0);
        // vm.expectRevert("not owner of token");
        vm.startPrank(bob);
        erc721.burn(0);
        uint bal = erc721.balanceOf(bob);
        assertEq(bal,(0));
    }

```
`Fail Test other than owner burn function by Bob Address :-`

```
function testFailBurn() public {
        erc721.mint(bob,0);
        vm.startPrank(alice);// Called by other address not owner
        erc721.burn(0);
    }
```
`Test approve function by Bob Address :-`

```

    function testApprove() public {
        erc721.mint(bob,0);
        vm.prank(bob);
        erc721.approve(alice,0);
        address _owner = erc721.ownerOf(0);
        assertEq(bob,_owner);
        address _approved = erc721.getApproved(0);
        assertEq(alice,_approved);
    }

```
`Test getApproved function by Bob Address :-`

```
function testGetApprove() public {
        erc721.mint(bob,0);
        vm.prank(bob);
        erc721.approve(alice,0);
        address _approved = erc721.getApproved(0);
        assertEq(_approved,alice);
    }
```
`Test setApprovalForAll function by Bob Address :-`

```
 function testSetApprovalForAll() public {
        erc721.mint(bob,0);
        vm.prank(bob);
        erc721.setApprovalForAll(alice,true);
        bool _approved = erc721.isApprovedForAll(bob,alice);
        assertEq(_approved,true);
    }
```

**Let's Tests the events :- **

`Test Transfer Event by Bob Address :-`

```
  function testTransferEvent() public {
        erc721.mint(bob,0);
        vm.expectEmit(true, true, true,false);
        emit Transfer(bob,alice,0);
        vm.prank(bob);
        erc721.safeTransferFrom(bob,alice,0);
    }
```


`Test Approval Event by Bob Address :-`

```
function testApprovalEvent() public{
        erc721.mint(bob,0);
        vm.expectEmit(true, true, true,false);
        emit Approval(bob,alice,0);
        vm.prank(bob);
        erc721.approve(alice,0);
    }
```

`Test ApprovalForAll Event by Bob Address :-`

```
 function testApprovalForAllEvent() public {
        erc721.mint(bob,0);
        vm.expectEmit(true, true, true,false);
        emit ApprovalForAll(bob,alice,true);
        vm.prank(bob);
        erc721.setApprovalForAll(alice,true);
    }
```

**So Here we complete the testing of functions and Events : 
let's Test them **

`forge build //for compilation`
`forge test --match-path test/Erc721.t.sol -vvv  // for testing`
`forge test --gas-report // for generating gas report`


**Access to Full Testing Contract :-**

```
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;


import "forge-std/Test.sol";
import "../src/Erc721.sol";


contract TestERC721 is Test{
    MyNFT public erc721;
    event Transfer(address indexed from, address indexed to, uint indexed id);
    event Approval(address indexed owner, address indexed spender, uint indexed id);
    event ApprovalForAll(
        address indexed owner,
        address indexed operator,
        bool approved
    );
    address public bob = address(1);
    address public alice= address(2);
    address public cat = address(3);
    function  setUp() public{
        erc721 = new MyNFT();
    }

    function testMintingERC721() public{
        erc721.mint(bob,0);
        address _owner = erc721.ownerOf(0);
        uint iud = erc721.balanceOf(bob);
        assertEq(iud,1);
        assertEq(bob,_owner);
    }

    function testOwnerOfToken() public{
        erc721.mint(bob,0);
        address _owner = erc721.ownerOf(0);
        assertEq(bob,_owner);
    }

    function testTransferFrom() public {
        erc721.mint(bob,0);
        vm.startPrank(bob);
        erc721.safeTransferFrom(bob,alice,0);
        address _owner = erc721.ownerOf(0);
        assertEq(alice,_owner);
        uint iud = erc721.balanceOf(alice);
        assertEq(iud,1);
    }   

    function testGetBalance() public {
        erc721.mint(bob,0);
        erc721.mint(bob,1);
        erc721.mint(bob,2);
        erc721.mint(bob,3);
        erc721.mint(bob,4);
        erc721.mint(bob,5);
        uint bal = erc721.balanceOf(bob);
        assertEq(bal,6);
    }

    function testOnlyOwnerBurn() public {
        erc721.mint(bob,0);
        // vm.expectRevert("not owner of token");
        vm.startPrank(bob);
        erc721.burn(0);
        uint bal = erc721.balanceOf(bob);
        assertEq(bal,(0));
    }

    function testFailBurn() public {
        erc721.mint(bob,0);
        vm.startPrank(alice);// Called by other address not owner
        erc721.burn(0);
    }

    function testApprove() public {
        erc721.mint(bob,0);
        vm.prank(bob);
        erc721.approve(alice,0);
        address _owner = erc721.ownerOf(0);
        assertEq(bob,_owner);
        address _approved = erc721.getApproved(0);
        assertEq(alice,_approved);
    }

    function testGetApprove() public {
        erc721.mint(bob,0);
        vm.prank(bob);
        erc721.approve(alice,0);
        address _approved = erc721.getApproved(0);
        assertEq(_approved,alice);
    }


    function testSetApprovalForAll() public {
        erc721.mint(bob,0);
        vm.prank(bob);
        erc721.setApprovalForAll(alice,true);
        bool _approved = erc721.isApprovedForAll(bob,alice);
        assertEq(_approved,true);
    }

    // Testing of events 

    function testTransferEvent() public {
        erc721.mint(bob,0);
        vm.expectEmit(true, true, true,false);
        emit Transfer(bob,alice,0);
        vm.prank(bob);
        erc721.safeTransferFrom(bob,alice,0);
    }


    function testApprovalEvent() public{
        erc721.mint(bob,0);
        vm.expectEmit(true, true, true,false);
        emit Approval(bob,alice,0);
        vm.prank(bob);
        erc721.approve(alice,0);
    }

    function testApprovalForAllEvent() public {
        erc721.mint(bob,0);
        vm.expectEmit(true, true, true,false);
        emit ApprovalForAll(bob,alice,true);
        vm.prank(bob);
        erc721.setApprovalForAll(alice,true);
    }

}
```

**GAS-REPORT**

![Gas-Report](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gzvtug9p8wszlqloo3ey.png)



---

Thank-you for reading this article ....
Comment if you have better Approach . 
Happy Coding ...