Skip to content

0xteddybear/smock-foundry

 
 

Repository files navigation

Version License: MIT

Smock Foundry

A plugin for foundry that automatically generates Solidity mocks for every contract in your project.

Features

  • Get rid of your folder of "mock" contracts and just use foundry.
  • Keep your tests simple with straightforward mock functions.
  • Mock up external calls and internal variables in a beautiful and orderly fashion.

Installation

You can install the plugin via yarn:

yarn add @defi-wonderland/smock-foundry --save-dev

Basic Usage

Creating mocks

To generate the mock contracts all you have to do is run:

yarn smock-foundry --contracts solidity/contracts

The smock-foundry command accepts the following options:

Option Default Notes
contracts The path to the solidity contracts to mock
root . The path to the root of the project
mocks ./test/smock The path to the generated mock contracts
ignore [] A list of directories to ignore, e.g. --ignore libraries

Be sure to gitignore the generated smock directory.

Using mocks

Let's say you have a Greeter contract in your project at contracts/Greeter.sol:

contract Greeter {
  string internal _greeting;

  constructor(string memory greeting) {
    _greeting = greeting;
  }

  function greet() public view returns (string memory) {
    return _greeting;
  }
}

After running the generator, you will have a mock contract located at ${mocks}/contracts/MockGreeter.sol:

contract MockGreeter is Greeter {
  function mock_call_greet(string memory __greeting) external {
    // Mocks the greet() function calls
  }

  function set__greeting(string memory greeting) public {
    // Sets the value of `greeting`
  }
}

The next step would be importing the mock contract in your unit tests, deploying it and allowing it to use the cheatcodes, specifically vm.mockCall.

import 'forge-std/Test.sol';

import { MockGreeter } from '/path/to/smock/contracts/MockGreeter.sol';
import { SmockHelper } from '/path/to/smock/SmockHelper.sol';

contract BaseTest is Test, SmockHelper {
  MockGreeter public greeter;

  function setUp() public {
    // The `deployMock` call is equivalent to
    // address _greeterAddress = address(new MockGreeter('Hello'));
    // vm.label(_greeterAddress, 'Greeter');
    // vm.allowCheatcodes(_greeterAddress);
    // return _greeterAddress;

    greeter = MockGreeter(
      deployMock('Greeter', type(Greeter).creationCode, abi.encode('Hello'))
    );
  }
}

Then enjoy the wonders of mocking:

// Mock the `greet` function to return 'Hola' instead of 'Hello'
greeter.mock_call_greet('Hola');

// Or you can achieve the same by setting the internal variable
greeter.set__greeting('Hola');

Gotchas

  • Please, note that if you want to mock internal functions, you must make them virtual. The tool will not generate mocks for internal functions that are not virtual.
  • Cannot set private variables and mock private functions.
  • Mocking of structs containing mappings is not supported.
  • Mocking of multi-dimensional arrays of structs is not supported.

Licensing

The primary license for Smock Foundry is MIT, see LICENSE.

Contributors

Maintained with love by Wonderland. Made possible by viewers like you.

About

Smock-style mocks for Foundry projects

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • TypeScript 53.7%
  • Solidity 40.4%
  • Handlebars 4.8%
  • Other 1.1%