Introducing Smock v2
Solidity devs: meet Smock v2. The Solidity mocking library. A collaboration between Optimism and the fantastic team over at DeFi Wonderland.
Smart contract testing has historically been… hard? If not hard, then just confusing. Way back in the early days of Solidity the best way to test a contract was to write another contract responsible for doing all the testing. This was a terrible idea for about 20 different reasons. I’ll name a few of the most important ones:
- You had to write your test code in Solidity.
- You had to re-compile your test contracts just to change your tests.
- Your test contracts and target contracts shared the same chain state.
It was a huge time sink for everyone involved. It was mostly okay because smart contracts were relatively simple back then. But, of course, this lack of testing infrastructure meant that contracts couldn’t be very complex.
It took a while, but we finally evolved to use JavaScript testing frameworks like Truffle to vastly improve the testing experience. We got to inherit some of the nice features of tools like chai and mocha. Our tests became at least somewhat legible. You could actually build contract systems with a reasonable amount of complexity.
Hardhat eventually came along and improved upon many of the things that Truffle, admittedly, did first. But Hardhat’s major advancement was its plugin system — developers now had the ability easily to manipulate their testing environment to an extent never really possible with Truffle.
Yet throughout all of this improvement, Solidity developers have still had to deal with one absolutely terrible pattern: mock contracts, written in Solidity, just to be able to unit test very specific functionality. I mean, really??? Here are a few reasons why this is so bad:
- You have to write your test code in Solidity.
- You have to re-compile your test contracts just to change your tests.
- Your test contracts and target contracts share the same chain state.
???
Yeah. Anyway. We fixed that.
Introducing: Smock v2. Contract mocking in JavaScript. More powerful than you can imagine. Never write a mock contract in Solidity again.
Features
Fake any contract
const myFake = await smock.fake('MyContract');
const myOtherFake = await smock.fake(myContractFactory);
const myOtherOtherFake = await smock.fake(myContractABI);
const myOtherOtherOtherFake = await smock.fake(myContractInstance);
Manipulate any contract function
myFake.myFunction.returns(1234);
myFake.myOtherFunction.returns({ myStructField: 1234 });
myFake.myOtherOtherFunction.returns((fnArg) => { return fnArg * 10 });
myFake.myOtherOtherOtherFunction.reverts(); // womp womp!
Make assertions about calls
expect(myFake.myFunction).to.have.been.calledOnce;
expect(myFake.myFunction).to.have.been.calledWith(1234);
expect(myFake.myFunction).to.have.been.calledBefore(myFake.myOtherFunction);
Create mocks backed by real contracts
const myMockFactory = await smock.mock('MyContract');
const myMock = await myMockFactory.deploy();// Does everything a fake can do!
myMock.myFunction.returns(5678);
Manipulate variables inside of mocks
await myMock.setVariable('myVariable', 1234);
await myMock.setVariable('myOtherVariable', { myStructValue: 1234 });
And so much more…
Do I really need to say anything else? Go try it out. It’ll change your life. Seriously.