RustBrock/Writing_Tests.md

109 lines
3.8 KiB
Markdown

# How to Write Tests
TAests are Rust functions that verify that non-test code is funcioning as expected
The bodies of test functions typically perform these three actions:
- Set up any needed data or state
- Run the code you want to test
- Assert that the resutls are what yo expect
Lets look at the features Rst provides specifically for writing tests that take these actions.
This incldes the `test` attribute, a few macros, and the `should_panic` attribute
## The Anatomy of a Test Function
A test in Rus is a function that is annotated with the `test` attribute.
Attributes are metadata about peices of Rust code
An example of this that we used in the past was the `derive` attribute which was used iwth structs in Ch5(Using Structs to Stucture Related Data)
To change a fucntion into a test function add `#[test]` on the line before `fn`
When you run your tests with the `cargo test` command
Rust will then builds a test runner binary that runs the annotated functions and reports whether each test function passes or fails.
Whenever we make a new library project with Cargo, a test module with a test function with a tet function in it is automaticakky generated for us
This module give a template for writing your tests.
This is great becuase you dont have to look up the syntax and structure every time you start a new project.
You can add as many additional test functions and as many modules as you want using that generated template
Find an example of this in the library/directory adder
Lets create the function `add`
Here is how to create a new library use this command
```
$ cargo new adder --lib
Created library `adder` project
$ cd adder
```
Here is what `adder` library should look like/ the generated code
```rust
pub fn add(left: usize, right: usize) -> usize {
left + right
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn it_works() {
let result = add(2, 2);
assert_eq!(result, 4);
}
}
```
Lets focus on the `it_works` function.
Note the `#[test]` annotation; this attribute indicates this is a test function, so that the test runner knows how to treat this function as a test
We could also have non-test functions in the `tests` module to help set up common scenarios or perform common operations, so we always need a way to indicate which are tests
This test example uses the `assert_eq!` macro to assert that `result`, which contains the result of adding 2 and 2, equlas 4.
This servers as an example of the format of a typical test
After the `cargo test` command runs all tests in our project
Here is the result
```
$ cargo test
Compiling adder v0.1.0 (file:///projects/adder)
Finished `test` profile [unoptimized + debuginfo] target(s) in 0.57s
Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
Doc-tests adder
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```
We can see that cargo compiled then ran the test.
We can see first `running 1 test`, then it shows the function name ``tests::it_works` and then the result of running that test is `ok`
It then shows the overall summary `test result: ok.` which means that all tests passed, and the portion that reads `1 passed; 0 failed` totals th number of tests that passed or failed
It's possible to mark a test as ignored so it doesn't run in a particular instance, that will be overed later in this ch
Because we havent it also shows `0 ignored`
The `0 measured` statistic is for benchmark tests that measure performance.
Benchmark tests are only avaialbe in nightly Rust, at the time of 2023 or the writing of the rust programmign language book 2023