Table Testing
Foundry v1.3.0 comes with support for table testing, which enables the definition of a dataset (the "table") and the execution of a test function for each entry in that dataset. This approach helps ensure that certain combinations of inputs and conditions are tested.
Test definition
In forge, table tests are functions named with table
prefix that accepts datasets as one or multiple arguments:
function tableSumsTest(TestCase memory testCaseSum) public
function tableSumsTest(TestCase memory testCaseSum, bool enable) public
The datasets are defined as forge fixtures which can be:
- storage arrays prefixed with
fixture
prefix and followed by dataset name - functions named with
fixture
prefix, followed by dataset name. Function should return an (fixed size or dynamic) array of values.
Examples
- Single dataset. In following example,
tableSumsTest
test will be executed twice, with inputs fromfixtureSums
dataset: once withTestCase(1, 2, 3)
and once withTestCase(4, 5, 9)
.
struct TestCase {
uint256 a;
uint256 b;
uint256 expected;
}
function fixtureSums() public returns (TestCase[] memory) {
TestCase[] memory entries = new TestCase[](2);
entries[0] = TestCase(1, 2, 3);
entries[1] = TestCase(4, 5, 9);
return entries;
}
function tableSumsTest(TestCase memory sums) public pure {
require(sums.a + sums.b == sums.expected, "wrong sum");
}
- Multiple datasets.
tableSwapTest
test will be executed twice, by using values at the same position fromfixtureWallet
andfixtureSwap
datasets.
struct Wallet {
address owner;
uint256 amount;
}
struct Swap {
bool swap;
uint256 amount;
}
Wallet[] public fixtureWallet;
Swap[] public fixtureSwap;
function setUp() public {
// first table test input
fixtureWallet.push(Wallet(address(11), 11));
fixtureSwap.push(Swap(true, 11));
// second table test input
fixtureWallet.push(Wallet(address(12), 12));
fixtureSwap.push(Swap(false, 12));
}
function tableSwapTest(Wallet memory wallet, Swap memory swap) public pure {
require(
(wallet.owner == address(11) && swap.swap) || (wallet.owner == address(12) && !swap.swap), "not allowed"
);
}