Skip to content

Commit a7819a8

Browse files
authored
Update doc: before test setup (#1246)
1 parent caeec39 commit a7819a8

File tree

1 file changed

+54
-0
lines changed

1 file changed

+54
-0
lines changed

src/forge/writing-tests.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,60 @@ such as `Ownable.sol`'s `onlyOwner` modifier, then the test contract `0xb4c...7e
5353
> Test functions must have either `external` or `public` visibility. Functions declared as `internal` or
5454
> `private` won't be picked up by Forge, even if they are prefixed with `test`.
5555
56+
### Before test setups
57+
58+
Unit and fuzz tests are stateless and are executed as single transactions, meaning that the state modified by a test won't be available for a different one (instead, they'll use the same state created by `setUp` call).
59+
It is possible to simulate multiple transactions in a single test, with a dependency tree, by implementing the `beforeTestSetup` function.
60+
61+
- `beforeTestSetup`: Optional function that configures a set of transactions to be executed before test.
62+
63+
```solidity
64+
function beforeTestSetup(
65+
bytes4 testSelector
66+
public returns (bytes[] memory beforeTestCalldata)
67+
```
68+
69+
where
70+
- `bytes4 testSelector` is the selector of the test for which transactions are applied
71+
- `bytes[] memory beforeTestCalldata` is an array of arbitrary calldata applied before test execution
72+
73+
> 💡 **Tip**
74+
>
75+
> This setup can be used for chaining tests or for scenarios when a test needs certain transactions committed before test run (e.g. when using `selfdestruct`).
76+
> The test fails if any of the configured transaction reverts.
77+
78+
For example, in contract below, `testC` is configured to use state modified by `testA` and `setB(uint256)` functions:
79+
```solidity
80+
contract ContractTest is Test {
81+
uint256 a;
82+
uint256 b;
83+
84+
function beforeTestSetup(
85+
bytes4 testSelector
86+
) public pure returns (bytes[] memory beforeTestCalldata) {
87+
if (testSelector == this.testC.selector) {
88+
beforeTestCalldata = new bytes[](2);
89+
beforeTestCalldata[0] = abi.encodePacked(this.testA.selector);
90+
beforeTestCalldata[1] = abi.encodeWithSignature("setB(uint256)", 1);
91+
}
92+
}
93+
94+
function testA() public {
95+
require(a == 0);
96+
a += 1;
97+
}
98+
99+
function setB(uint256 value) public {
100+
b = value;
101+
}
102+
103+
function testC() public {
104+
assertEq(a, 1);
105+
assertEq(b, 1);
106+
}
107+
}
108+
```
109+
56110
### Shared setups
57111

58112
It is possible to use shared setups by creating helper abstract contracts and inheriting them in your test contracts:

0 commit comments

Comments
 (0)