Cairo natively have the ability of running tests to verify that your code (none-test) code is functioning as expected through Cairo functions referred to as Tests
. The Test functions
typically:
- Assert that the results of your code is as expected,
- Is able to set up any needed state or data for your test
- And finally, able to run the code you want to test.
Test Functions
in Cairo uses Cairo specific features including the test
attribute, should_panice
attribute and the assert
function. Cairo tests are run with the cairo-test
command.
A test function
in cairo at its simplest should be annotated with the test
attribute. Attributes are basically metadata about pieces of Cairo code and are presented as #[**]
with the name of the attribute between the square brackets. Therefore, our test
attribute would be presented as #[test]
. As you have seen by now, an attribute is placed above function declaration fn
.
** Let's code test**
First, let us create a new project and we call it addition
which will add two numbers. We use Scarb for projects therefore, we create the new project as scarb new addition
. You should have the following files
addition
├── cairo_project.toml
├── Scarb.toml
└── src
└── lib.cairo
cairo_project.toml
file is important in running cairo tests. This is the configuration file for Cairo projects which is required to run cairo-test .
comand in order to run the code of the crate. This file is not currently implemented by Scarb and therefore might not be present in your code.
In the event that you do not see cairo_project.toml
kindly create a file and name it as such and input the following:
[crate_roots]
addition = "src"
In lib.cairo
file put the following code:
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert(result == 4, 'result is not 4');
}
}
Note the #[test]
annotation attribute indicates that this is a test function therefore the test runner would treat this function as a test. It is important to use the attribute on #[test]
on test functions as it is possible to have non-test functions in the tests module in order to set up specific scenarios that we would want to test.
In the example above, the test function uses the assert
function which asserts that the results of adding two numbers 2 and 2 is 4.
We then run cairo-test .
command to run all tests with an output like this:
$ cairo-test .
running 1 tests
test addition::lib::tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 filtered out;
cairo-test
compiled and run the test. The overall summary test result: ok.
means that all the tests passed, and the portion that reads 1 passed; 0 failed
totals the number of tests that passed or failed.
Let us consider making a test that fails. We can add another test in our test function and name it another
, therefore, our lib.cairo
file looks like
#[cfg(test)]
mod tests {
#[test]
fn it_works() {
let result = 2 + 2;
assert(result == 4, 'result is not 4');
}
#[test]
fn another() {
let result = 2 + 2;
assert(result == 6, 'Make this test fail');
}
}
Note that the second test, another
has the attribute #[test]
above it.
When we run the test with caro-test .
we get the following results.
$ cairo-test .
running 2 tests
test addition::lib::tests::it_works ... ok
test addition::lib::tests::another ... fail
failures:
addition::lib::tests::another - panicked with [1725643816656041371866211894343434536761780588 ('Make this test fail'), ].
Error: test result: FAILED. 1 passed; 1 failed; 0 ignored
Instead of ok, the line addition::lib::tests::another
shows fail. A new section appears between the individual results and the summary. It displays the detailed reason for each test failure. In this case, we get the details that another failed because it panicked with [1725643816656041371866211894343434536761780588 ('Make this test fail'), ]
in the src/lib.cairo file
The assert
function in Cairo uses boolean operations and evaluates a test to either true
or false
. The assert
function evaluates to true
when our code functions as expected, and therefore, nothing happens and our test passes. However, if the test fails, it evaluates to a false
and the assert function calls panic ()
to cause the test to fail with a message we define in our test argument. In our case, we defined Make this test fail
in the another test case. As such, we can conclude that checking tests with assert
is useful when evaluating return values.