外云南吧 关注:9贴子:48
  • 1回复贴,共1
Rust treats testing as a first-class construct; all tools in the ecosystem
supports testing. The compiler provides a built-in configuration attribute
that designates a module for testing. There is also a test attribute that
designates functions as tests. When Cargo generates a project from scratch,
it sets up this boilerplate. Let's look at an example project; we will call it
factorial. It will export a macro that computes the factorial given an
integer. Since we have conveniently written such a macro before, we will
just re-use that code here. Note that since this crate will be used as a
library, this does not have a main function:
# cargo new factorial --lib
# cargo test
Compiling factorial v0.1.0 (file:///Users/Abhishek/Desktop/rust-
book/src/ch2/factorial)
Finished dev [unoptimized + debuginfo] target(s) in 1.6 secs
Running target/debug/deps/factorial-364286f171614349
running 1 test
test tests::it_works ... ok
test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered
out
Doc-tests factorial
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered
out
Running cargo test runs the stub tests that Cargo generates for us. We will
copy the code for the factorial macro to the lib.rs, which will look like
this:
// chapter2/factorial/src/lib.rs
#[allow(unused_macros)]
#[macro_export]
macro_rules! factorial {
($x:expr) => {
{
let mut result = 1;
for i in 1..($x+1) {
result = result * i;
}
result
}
};
}
#[cfg(test)]
mod tests {
#[test]
fn test_factorial() {
assert_eq!(factorial!(5), 120);
}
}
We also added a test to make sure factorial actually works as one would
expect. The #[macro_export] attribute tells the compiler that this macro is
to be used outside the crate. The compiler built-in assert_eq! macro checks
that the two arguments are indeed equal. We also need to put
the #[allow(unused_macros)] attribute since, without it, the compiler will
complain that the macro is not being used in non-test code. If we add one
more test that looks like this:
#[test]
fn test_factorial_fail() {
assert_eq!(factorial!(5), 121);
}
This is obviously wrong, and as expected, fails and gives us a descriptive
error. The compiler also supports an attribute called #[should_panic] that
marks tests that should panic. In this case, the tests pass only if there is a
panic. Another way of writing tests is in the documentation which is also
run on a Cargo invocation.
This is a very important tool in documenting code with working examples,
which are guaranteed to work as the codebase evolves. Let's go ahead and
add some doctest for our factorial macro:
// chapter2/factorial/src/lib.rs
/// The factorial crate provides a macro to compute factorial of a
given
/// integer
/// # Examples
///
/// ```
/// # #[macro_use] extern crate factorial;
/// # fn main() {
/// assert_eq!(factorial!(0), 1);
/// assert_eq!(factorial!(6), 720);
/// # }
/// ```
///
#[macro_export]
macro_rules! factorial {
($x:expr) => {
{
let mut result = 1;
for i in 1..($x+1) {
result = result * i;
}
result
}
};
}
Doctests for macros differ a bit from doctests for everything else in the
following way:
• They must use the #[macro_use] attribute to mark that the macro is
being used here. Note that an external crate that depends on the crate
that exports a macro must use that attribute too.
• They must define the main function and include an extern crate
directive in the doctests. For everything else, the compiler generates
the main function as needed. The extra # marks hide those from the
generated documentation.
In general, the tests module, doctests, and the #[test] attributes should be
used only for unit tests. Integration tests should be placed in a top-level
tests directory.


IP属地:四川1楼2023-01-02 12:28回复
    The Rust team is working on adding support for running
    benchmarks in the test system. This is only available on nightly
    for now.


    IP属地:四川2楼2023-01-02 12:29
    回复