Fuzz Testing
In many cases, a test needs to verify function behavior for multiple possible values. While it is possible to come up with these cases on your own, it is often impractical, especially when you want to test against a large number of possible arguments.
ℹ️ Info Currently,
snforge
fuzzer only supports using randomly generated values. This way of fuzzing doesn't support any kind of value generation based on code analysis, test coverage or results of other fuzzer runs. In the future, more advanced fuzzing execution modes will be added.
Random Fuzzing
To convert a standard test into a random fuzz test, you need to add parameters to the test function
and include the #[fuzzer]
attribute.
These arguments can then be used in the test body.
The test will be run many times against different randomly generated values.
fn sum(a: felt252, b: felt252) -> felt252 {
return a + b;
}
#[cfg(test)]
mod tests {
use super::sum;
#[test]
#[fuzzer]
fn test_sum(x: felt252, y: felt252) {
assert_eq!(sum(x, y), x + y);
}
}
Then run snforge test
like usual.
$ snforge test
Output:
Collected 2 test(s) from fuzz_testing package
Running 2 test(s) from src/
[PASS] fuzz_testing::with_parameters::tests::test_sum (runs: 22, gas: {max: ~124, min: ~121, mean: ~123.00, std deviation: ~0.90})
[PASS] fuzz_testing::basic_example::tests::test_sum (runs: 256, gas: {max: ~124, min: ~121, mean: ~123.00, std deviation: ~0.81})
Tests: 2 passed, 0 failed, 0 skipped, 0 ignored, 0 filtered out
Fuzzer seed: [..]
Types Supported by the Fuzzer
Fuzzer currently supports generating values for these types out of the box:
felt252
u8
,u16
,u32
,u64
,u128
,u256
i8
,i16
,i32
,i64
,i128
ByteArray
To use other types, it is required to implement the Fuzzable
trait for them.
Providing non-fuzzable types will result in a compilation error.
Fuzzer Configuration
It is possible to configure the number of runs of the random fuzzer as well as its seed for a specific test case:
fn sum(a: felt252, b: felt252) -> felt252 {
return a + b;
}
#[cfg(test)]
mod tests {
use super::sum;
#[test]
#[fuzzer(runs: 22, seed: 38)]
fn test_sum(x: felt252, y: felt252) {
assert_eq!(sum(x, y), x + y);
}
}
It can also be configured globally, via command line arguments:
$ snforge test --fuzzer-runs 1234 --fuzzer-seed 1111
Or in Scarb.toml
file:
# ...
[tool.snforge]
fuzzer_runs = 1234
fuzzer_seed = 1111
# ...