DEV Community

Cover image for Foundry Test : ERC721 SOL (Postmortem)
Neeraj Choubisa
Neeraj Choubisa

Posted on

Foundry Test : ERC721 SOL (Postmortem)

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);
    }
Enter fullscreen mode Exit fullscreen mode

Test Owner function by Bob Address :-

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

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);
    }   
Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

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));
    }

Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

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);
    }

Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

*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);
    }
Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

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);
    }
Enter fullscreen mode Exit fullscreen mode

*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);
    }

}
Enter fullscreen mode Exit fullscreen mode

GAS-REPORT

Gas-Report


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

Top comments (0)