Running tests with Cargo

Cargo also supports running tests and benchmarks. In-depth testing and benchmarking is covered in Chapter 3, Tests, Documentation, and Benchmarks. In this section, we will go over a brief introduction on how to run tests using Cargo. We'll write tests for a library crate. To work our way through this section, let's create a crate by running cargo new myexponent --lib:

A library crate is similar to a binary crate. The difference is that instead of src/main.rs and a main function inside as an entry point, we have src/lib.rs with a trivial test function, it_works, which is marked with a #[test] annotation. We can run the it_works test function right away using cargo test and see it pass:

Now,  let's try a bit of Test Driven Development (TDD) with Cargo. We will extend this library by adding a pow function ,with which the users of our library can calculate the exponent for a given number. We'll write a test for this function that initially fails and then fill in the implementation until it works. Here's the new src/lib.rs, featuring the pow function without any implementation:

// myexponent/src/lib.rs

fn pow(base: i64, exponent: usize) > i64 {
unimplemented!();
}

#[cfg(test)]
mod tests {
use super::pow;
#[test]
fn minus_two_raised_three_is_minus_eight() {
assert_eq!(pow(-2, 3), -8);
}
}

Don't worry about the details right now. We have created a single pow function that takes in a base as i64 and a positive exponent as usize, and returns a number that's been raised to the exponent. Under mod tests {, we have a test function called minus_two_raised_three_is_minus_eight that does a single assertion. The assert_eq! macro checks for the equality of the two values that were passed to it. If the left argument is equal to the right argument, the assertion passes; otherwise, it throws an error and the compiler reports the failed test. If we run cargo test, the unit tests obviously fails for pow invocation because we have an unimplemented!() macro invocation there:

In brief, unimplemented!() is just a convenient macro to mark unfinished code or code that you wish to implement later, but want the compiler to compile it anyway without giving a type error. Internally, this calls panic! with a message, "not yet implemented". It can be used in cases where you are implementing multiple methods of a trait. For instance, you start implementing one method, but you haven't planned on the implementation for other methods. When compiled, you would get compile errors for the other unimplemented methods if you just placed the function with an empty body. For these methods, we can place an unimplemented!() macro call inside them, just to make the type checker happy and compile for us, and offload the errors at runtime. We will look at more convenient macros like this in Chapter 9, Metaprogramming with Macros.

Now, let's fix this problem by implementing a quick and dirty version of the pow function and try again:

// myexponent/src/lib.rs

pub fn pow(base: i64, exponent: usize) -> i64 {
let mut res = 1;
if exponent == 0 {
return 1;
}
for _ in 0..exponent {
res *= base as i64;
}
res
}

Running Cargo test gives the following output:

This time, the test passes. Well, that's the basics. We'll do more testing in Chapter 3, Tests, Documentation, and Benchmarks.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset