How Can I Mock the Time for Solidity Tests
Mock objects are a common design blueprint in object-oriented programming. Coming from the sometime French word 'mocquer' with the meaning of 'making fun of', it evolved to 'imitating something real' which is actually what we are doing in programming. Please simply make fun of your smart contracts if you desire to, only mock them whenever you can. It makes your life easier.
Mocking a contract essentially means creating a second version of that contract which behaves very similar to the original one, but in a way that can be hands controlled by the programmer. You ofttimes terminate up with complex contracts where you lot just want to unit of measurement-test small parts of the contract. The problem is what if testing this small office requires a very specific contract state that is hard to end up in?
Y'all could write complex test setup logic everytime that brings in the contract in the required state or you write a mock. Mocking a contract is easy with inheritance. Just create a second mock contract that inherits from the original ane. At present you can override functions to your mock. Let u.s. encounter it with an example.
We employ an example ERC-20 contract that has an initial private time. The possessor can manage private users and only those volition be immune to receive tokens at the kickoff. Once a sure time has passed, anybody will be allowed to use the tokens. If you lot are curious, nosotros are using the _beforeTokenTransfer
hook from the new OpenZeppelin contracts v3.
one pragma solidity ^0.6.0;
2
3 import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
4 import "@openzeppelin/contracts/access/Ownable.sol";
5
six contract PrivateERC20 is ERC20, Ownable {
seven mapping (address => bool) public isPrivateUser;
viii uint256 private publicAfterTime;
9
ten constructor(uint256 privateERC20timeInSec) ERC20("PrivateERC20", "PRIV") public {
11 publicAfterTime = now + privateERC20timeInSec;
12 }
13
14 part addUser(address user) external onlyOwner {
15 isPrivateUser[user] = true;
xvi }
17
xviii function isPublic() public view returns (bool) {
19 return now >= publicAfterTime;
20 }
21
22 function _beforeTokenTransfer(address from, accost to, uint256 amount) internal virtual override {
23 super._beforeTokenTransfer(from, to, amount);
24
25 require(_validRecipient(to), "PrivateERC20: invalid recipient");
26 }
27
28 function _validRecipient(accost to) private view returns (bool) {
29 if (isPublic()) {
30 return true;
31 }
32
33 return isPrivateUser[to];
34 }
35 }
36
Show all
Copy
And at present let's mock it.
1 pragma solidity ^0.six.0;
2 import "../PrivateERC20.sol";
3
4 contract PrivateERC20Mock is PrivateERC20 {
v bool isPublicConfig;
vi
seven constructor() public PrivateERC20(0) {}
viii
nine function setIsPublic(bool isPublic) external {
10 isPublicConfig = isPublic;
11 }
12
xiii office isPublic() public view returns (bool) {
14 return isPublicConfig;
15 }
16 }
17
Prove all
Copy
You volition get ane of the post-obit fault letters:
-
PrivateERC20Mock.sol: TypeError: Overriding function is missing "override" specifier.
-
PrivateERC20.sol: TypeError: Trying to override non-virtual function. Did you forget to add "virtual"?.
Since we are using the new 0.six Solidity version, we have to add together the virtual
keyword for functions that can be overriden and override for the overriding part. And so let us add together those to both isPublic
functions.
Now in your unit of measurement tests, you can use PrivateERC20Mock
instead. When y'all want to test the behaviour during the private usage time, use setIsPublic(false)
and likewise setIsPublic(true)
for testing the public usage time. Of course in our case, we could just use fourth dimension helpers to change the times accordingly also. But the idea of mocking should exist clear now and you can imagine scenarios where it is not every bit easy every bit but advancing the time.
It can become messy if you have to create another contract for every single mock. If this bothers yous, you lot can have a look at the MockContract library. It allows y'all to override and alter behaviours of contracts on-the-fly. However, it works merely for mocking calls to another contract, so it would not piece of work for our example.
The powers of mocking exercise not end there.
- Adding functions: Non only overriding a specific function is useful, but besides simply adding additional functions. A good example for tokens is only having an additional
mint
part to allow any user to go new tokens for gratis. - Usage in testnets: When you lot deploy and exam your contracts on testnets together with your Dapp, consider using a mocked version. Avert overriding functions unless yous really have to. You want to test the real logic later all. Merely calculation for instance a reset function tin can exist useful that merely resets the contract land to the beginning, no new deployment required. Plain yous would not want to have that in a Mainnet contract.
Last edit:
,
Invalid DateTime
Source: https://ethereum.org/en/developers/tutorials/how-to-mock-solidity-contracts-for-testing/
0 Response to "How Can I Mock the Time for Solidity Tests"
Post a Comment