Skip to content

Instantly share code, notes, and snippets.

@fvictorio
Created July 20, 2021 11:52
Show Gist options
  • Save fvictorio/8dfee19ec4925a8a0d85cb05a112bbb2 to your computer and use it in GitHub Desktop.
Save fvictorio/8dfee19ec4925a8a0d85cb05a112bbb2 to your computer and use it in GitHub Desktop.
Hardhat: stubs and mocks

If you want to test a contract that depends on other contract, but you don't own the latter contract (or you do but you want to test the first contract in isolation), you need to either stub or mock that dependency.

If you are not sure about the difference between a stub and a mock, check this StackOverflow question

Stubbing

If the contract you are testing receives its dependency in some way, you can write a stub contract and use that in your tests. It would be something like this:

contract ContractToTest {
  Dependency dependency;
  
  constructor (Dependency _dependency) {
    dependency = _dependency;
  }
  
  function functionToTest() public {
    // uses `dependency.f` somehow
  }
}

contract StubDependency {
  uint fakeValue;
  
  constructor (uint _fakeValue) {
    fakeValue = _fakeValue;
  }
  
  function f() public returns (uint) {
    return fakeValue;
  }
}

And then in your tests you would deploy StubDependency and use that address when you deploy your instance of ContractToTest

Mocking

There are two libraries you can use to mock a contract.

The first one is Waffle. To use this, you should install and use hardhat-waffle and then make sure that you use deployMockContract from the waffle instance in the Hardhat Runtime Environment:

const { waffle } = require("hardhat")
const { deployMockContract } = waffle

Don't import deployMockContract from @ethereum-waffle/mock-contract as the Waffle's docs do.

The second library you can use is smock. Check its docs to learn how to use it.

hardhat_setCode

This is an advanced method and you should only use it if none of the previous options work for you. The hardhat_setCode RPC method lets you change the bytecode of an address while preserving its storage. So you could write a stub contract, get its bytecode (for example, by just deploying it and getting the resulting code, or using the compilation output), and then replace the contract your contract depends on with the stubbed bytecode. This could be useful if you are using mainnet forking and use some existing contract.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment