Github repository: https://github.com/caveofprogramming/rust
A Library Function That Calculates Factorials
It’s only possible to create tests in Rust for library code.
Therefore I’m going to create a library called ‘numerical’ like this:
cargo new numerical --lib
Now, since I’d like to also use the library code from a binary, I create a file called main.rs
in the src folder, and add a main
function into it.
It’s now possible to run this code as a binary executable with cargo run
, or to just build the binary and the library using cargo build
. Since the library includes dummy tests, we can run the tests with cargo test
.
I’ll create another file in src/ called numeric.rs, and in there I’ll add a recursive function for calculating factorials.
Then I’ll make main.rs use the factorial function. I also need to make lib.rs load the numeric module.
We now have the following files:
main.rs:
lib.rs:
numeric.rs:
When I run this as a binary with cargo run
, the output is 6
.
Adding Unit Tests
According to the documentation, unless my brain has failed to grasp it properly, unit tests (tests that test individual units of the code such as functions) are typically placed in the same file where they are defined.
Therefore I’ll add a submodule into numeric.rs.
The #[cfg(test)]
annotation on the submodule says that it should be loaded when cargo
is run with test configuration, i.e. when cargo test
is executed.
Individual unit tests are marked with #[test]
.
assert_eq!
and assert!
can be used to check the results of tests.
.We can run this test with cargo test
, and it passes.
Multiple Tests
I’ve modified the test submodule by adding two more tests:
One of these tests is marked with #[ignore]. It won’t be run by default.
To run all tests, including the ignored tests, we can use:
cargo test -- --include-ignored
To run only the ignored tests, we can use:
cargo test -- --ignored
Testing Panic
We can test code that should panic using the should_panic specification. This optionally allows us to specify a substring that should be found in the panic message.
Here I’ve artificially added a panic! into the test itself, which would normally be expected to come from the code under test. Unless a panic occurs and the text contains the string “bad”, this test fails.
Returning Result
Instead of using assert! or assert_eq! it’s also possible to return a Result
. The following test passes if it returns Ok
and fails if it returns Error
.
Integration Tests
The above tests are all unit tests, that test software units. It’s also possible to create integration tests: tests external to a library that test how the library functions work together.
I’ve created a file called test_numeric.rs (but the name isn’t important) and put it in a folder called tests/
, parallel to src/.
In this case there’s no need to put the tests in a submodule, and the library functions can be imported normally, using the package name.
test_numeric.rs (in a tests folder parallel to src/):
These tests will also run automatically when you run cargo test
.