Testing Solidity

Based on notes taken while migrating me3 contracts from Hardhat to Foundry

Foundry

A rewrite of #Dapptools using Rust: https://github.com/gakonst/foundry/

Different failure checks

Sample contract that will be used for testing:

contract Lol {
  function betterBeOne (int x) external {
    require(x == 1, "x needs to be 1");
  }
}

==== try/catch with revert/require ====

Using a try/catch, run the function that is expected to fail. If it does not enter the catch it is because the function passed when it should not have. In this case, we force the test to fail by using revert(). When the function enters the catch block, we are on the right path. We can then use a require to validate any parts of the contract to make sure it was the correct failure.

This would be a good way to test many different require statements in the called function.

function testIsNotOne () public {
  try lol.betterBeOne(0) {
    revert();
  } catch Error(string memory error) {
    require(
      keccak256(abi.encodePacked(error)),
      keccak256("x needs to be 1")
    );
  }
}

testFail

When you expect a test to fail but don't need to check the message, you can start your function name with testFail and it will pass as long as a failure occurs

function testFailWhenNotOne () public {
  lol.betterBeOne(0);
}

ds-test

Unit testing Solidity in Solidity, written by dapphub: https://github.com/dapphub/ds-test

contract TestLol is DSTest {
  Lol public lol;
  
  function setUp () public {
    lol = new Lol();
  }
    
  function testIsNotOne () public {
    try lol.betterBeOne(0) {
      fail();
    } catch Error(string memory error) {
      assertEq(error, "x needs to be 1");
    }
  }
}

Hardhat

Deploying third-party contracts

If you interact with existing contracts, there are two methods that you can use to test with them:

  1. fork the network the contracts exist on
  2. if they are open source, deploy the contracts into the test network

To deploy existing contracts on your network, you can create an importer contract. Here is an example using ENS contracts:

// ENSDeploy.sol
// SPDX-License-Identifier: MIT

import "@ensdomains/ens-contracts/contracts/registry/ENSRegistry.sol";
import "@ensdomains/ens-contracts/contracts/registry/FIFSRegistrar.sol";
import "@ensdomains/ens-contracts/contracts/registry/ReverseRegistrar.sol";

The contracts can be added to the project with:

npm i --save-dev @ensdomains/ens-contracts