Mocking Solidity smart contracts with Waffle

Marek Kirejczyk
May 22, 2020 · 3 min read

Testing smart contracts written in Solidity is still somewhat cumbersome. One subtle reason is that we keep writing our unit tests as if they were integration tests and not how we would write unit tests.

Surprised? Take a look at the diagram below. It represents a test for a hypothetical on-chain market that allows buying ERC721 tokens for ERC20 tokens. To test even a basic functionality, one needs to touch several other smart contracts.

Testing without mocks.

How much easier would it be if we could test a single contract in isolation? Like in the picture below:

Testing with mocks.

Mocking smart contracts

Much as we find it to be a good practice, it is also a very limited method, and it complicates tests in several ways:

  • increases the amount of code in Solidity to write, build and maintain
  • limits test flexibility to a predefined mock functionality
  • makes test setup more complex, as each test might require deploying several contracts and advance them to a specific state
  • makes tests execute slowly (especially due to complex setup)

In practice, you see many tests that deploy and establish a whole predefined smart contract system and advance it to a specific state to test simple features.

Hoping to make a significant improvement, we introduced a new feature in Waffle 2.5.0 — dynamic mocking.

Dynamic mocking

const mockERC20 = await deployMockContract(sender, IERC20.abi);

Now, you can easily test a functionality in isolation. Let’s examine a simple smart contract that allows verifying if msg.sender has at least a predetermined number of tokens:

pragma solidity ^0.5.15;

interface IERC20 {
function balanceOf(address account) ... returns (uint256);
...
}

contract AmIRichAlready {
IERC20 private tokenContract;
uint private constant RICHNESS = 1000000 * 10 ** 18; constructor (IERC20 _tokenContract) public {
tokenContract = _tokenContract;
}

function check() public view returns (bool) {
uint balance = tokenContract.balanceOf(msg.sender);
return balance > RICHNESS;
}
}

Now, we can test our contract extensively without adding extra Solidity code that would implement an ERC20 mock token or import external libraries. Let’s start with creating a contract and connect it to a mock:

const [wallet, otherWallet] = new MockProvider().getWallets();beforeEach(async () =>  {
mockERC20 = await deployMockContract(wallet, IERC20.abi);
contract = await deployContract(wallet, AmIRichAlready, [mockERC20.address]);
});

And we can define what the mock should return and test the behavior of our method right away:

it('wallet has little coins', async () => {
await mockERC20.mock.balanceOf.returns(parseEther('999999'));
expect(await contract.check()).to.be.equal(false);
});

Check out the full example on Waffle GitHub.

Defining behaviour

await mockContract.mock.<nameOfMethod>.returns(<value>)
await mockContract.mock.<name>.withArgs(<args>).returns(<value>)
await mockContract.mock.<nameOfMethod>.reverts()
await mockContract.mock.<name>.withArgs(<args>).reverts()

Detailed documentation for mocking functionality is available here.

Warning: Experimental

We are Ethworks. A truly remarkable team for your blockchain project.

Find us on Twitter, Dribbble and GitHub.

Ethworks

On the blockchain, software engineering and running a company.

Sign up for 💡 Waffle News 💡

By Ethworks

Best practices in testing smart contracts with Waffle: our sweeter and simpler library built for Ethereum developers Take a look.

By signing up, you will create a Medium account if you don’t already have one. Review our Privacy Policy for more information about our privacy practices.

Check your inbox
Medium sent you an email at to complete your subscription.

Ethworks

Software is eating the world. Blockchain is eating money. Ethworks is cooking.

Marek Kirejczyk

Written by

Ethereum blockchain Engineer. Ethworks, Universal Login.

Ethworks

Software is eating the world. Blockchain is eating money. Ethworks is cooking.

Medium is an open platform where 170 million readers come to find insightful and dynamic thinking. Here, expert and undiscovered voices alike dive into the heart of any topic and bring new ideas to the surface. Learn more

Follow the writers, publications, and topics that matter to you, and you’ll see them on your homepage and in your inbox. Explore

If you have a story to tell, knowledge to share, or a perspective to offer — welcome home. It’s easy and free to post your thinking on any topic. Write on Medium

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store