Unit testing
Tests are Cairo functions that verify that the non-test code is functioning in the expected manner. The bodies of test functions typically perform some setup, run the code we want to test, then assert whether the results are what we expect.
Most unit tests go into a tests mod with the #[cfg(test)] attribute.
Test functions are marked with the #[test] attribute.
Tests fail when something in the test function panics. There are some helper macros:
assert!(expression)- panics if expression evaluates tofalse.assert_eq!(left, right)andassert_ne!(left, right)- testing left and right expressions for equality.assert_lt!(left, right)andassert_gt!(left, right)- testing left and right expressions for less than and greater than respectively.assert_le!(left, right)andassert_ge!(left, right)- testing left and right expressions for less than or equal to and greater than or equal to respectively.
// Basic add example
fn add(a: u32, b: u32) -> u32 {
a + b
}
// This is a really bad adding function, its purpose is to fail in this
// example.
fn bad_add(a: u32, b: u32) -> u32 {
a - b
}
#[cfg(test)]
mod add_tests {
// Note this useful idiom: importing names from outer (for mod tests) scope.
use super::*;
#[test]
fn test_add() {
assert_eq!(add(1, 2), 3);
}
#[test]
fn test_bad_add() {
// This assert would fire and test will fail.
// Please note, that private functions can be tested too!
assert_eq!(bad_add(1, 2), 3);
}
}
Tests can be run with scarb test. To run specific tests, one may specify the test name to scarb test command. To run multiple tests one may specify part of a test name that matches all the tests
that should be run. Here, we run all the tests in the add_tests module.
$ scarb test add
Running test unit_testing (snforge test)
Blocking waiting for file lock on registry db cache
Compiling test(listings/testing/unit_testing/Scarb.toml)
Finished `dev` profile target(s) in 6 seconds
Collected 4 test(s) from unit_testing package
Running 4 test(s) from src/
[PASS] unit_testing::add_tests::test_add (gas: ~1)
[PASS] unit_testing::ignore_tests::test_add (gas: ~1)
[FAIL] unit_testing::add_tests::test_bad_add
Failure data:
0x7533325f737562204f766572666c6f77 ('u32_sub Overflow')
[PASS] unit_testing::ignore_tests::test_add_hundred (gas: ~1)
Tests: 3 passed, 1 failed, 0 skipped, 0 ignored, 4 filtered out
Failures:
unit_testing::add_tests::test_bad_add
Testing panics
To check functions that should panic under certain circumstances, use attribute
#[should_panic]. This attribute accepts optional parameter expected: with
the text of the panic message. If your function can panic in multiple ways, it helps
make sure your test is testing the correct panic.
fn divide_non_zero_result(a: u32, b: u32) -> u32 {
if b == 0 {
panic!("Divide-by-zero error")
} else if a < b {
panic!("Divide result is zero")
}
a / b
}
#[cfg(test)]
mod divide_tests {
use super::*;
#[test]
fn test_divide() {
assert_eq!(divide_non_zero_result(10, 2), 5);
}
#[test]
#[should_panic]
fn test_any_panic() {
divide_non_zero_result(1, 0);
}
#[test]
#[should_panic(expected: "Divide result is zero")]
fn test_specific_panic() {
divide_non_zero_result(1, 10);
}
}
Running these tests gives us:
$ scarb test divide
Running test unit_testing (snforge test)
Compiling test(listings/testing/unit_testing/Scarb.toml)
Finished `dev` profile target(s) in 6 seconds
Collected 3 test(s) from unit_testing package
Running 3 test(s) from src/
[PASS] unit_testing::divide_tests::test_divide (gas: ~1)
[PASS] unit_testing::divide_tests::test_any_panic (gas: ~1)
Success data:
"Divide-by-zero error"
[PASS] unit_testing::divide_tests::test_specific_panic (gas: ~1)
Tests: 3 passed, 0 failed, 0 skipped, 0 ignored, 5 filtered out
Ignoring tests
Tests can be marked with the #[ignore] attribute to exclude some tests. Ignored tests can be run
with command scarb test -- --ignored
fn add_two(a: u32, b: u32) -> u32 {
a + b
}
#[cfg(test)]
mod ignore_tests {
use super::*;
#[test]
fn test_add() {
assert_eq!(add_two(2, 2), 4);
}
#[test]
fn test_add_hundred() {
assert_eq!(add_two(100, 2), 102);
assert_eq!(add_two(2, 100), 102);
}
#[test]
#[ignore]
fn ignored_test() {
assert_eq!(add_two(0, 0), 0);
}
}
$ scarb test -- --ignored
Running test unit_testing (snforge test)
Compiling test(listings/testing/unit_testing/Scarb.toml)
Finished `dev` profile target(s) in 5 seconds
Collected 1 test(s) from unit_testing package
Running 1 test(s) from src/
[PASS] unit_testing::ignore_tests::ignored_test (gas: ~1)
Tests: 1 passed, 0 failed, 0 skipped, 0 ignored, 7 filtered out