Write the test

In front end development, third-party JEST libraries are often used for unit testing, but rust has built in testable functionality for developers

How to Write tests

Testing in any language involves the following three steps:

  1. Prepare the required data or status.
  2. Call the code you want to test.
  3. The assertion runs as expected.

Test the composition of the function

Add #[test] to the top line of the fn keyword to turn the function into a test function, and then run the test using cargo test:

#[test]
fn it_works() {
  assert_eq!(2 + 2.4);
}
Copy the code

In the tests, if panic! Causes the test to fail:

#[test]
fn another() {
  panic!("Something went wrong.")}Copy the code

assert! Check if the result is true:

#[test]
fn is_true() {
  let is_eq = 2 > 1;
  assert!(is_eq);
}
Copy the code

assert_eq! Check if the two data are the same:

#[test]
fn is_eq() {
  // assert_eq! And assert_ne! Macros use == and! Respectively. = operator to determine,
  // And use the debugging output format {:? } Print out the parameter values.
  This means that their parameters must implement both PartialEq and Debug traits.
  #[derive(Debug, PartialEq)]
  struct Rect {
    width: u32,
    height: u32,}let rect1 = Rect {
    width: 150,
    height: 100};letrect2 = Rect { .. rect1 };assert_eq!(rect1, rect2);
}
Copy the code

assert_ne! Check if the two data are different:

#[test]
fn is_ne() {
  fn add(a: i32, b: i32) - >i32 {
    a + b
  }
  assert_ne!(add(1.2), 4)}Copy the code

Add a custom error message:

#[test]
fn custom_error() {
  let a = 1;
  let b = 2;
  
  // All arguments to the assertion function after the necessary arguments are passed to format! Macro for printing
  assert!(a > b, "{} should be greater than {}", a, b);
  assert_eq!(a, a, "{} should equal", a);
  assert_ne!(a, b, "{} should not equal {}", a, b);
}
Copy the code

Mark the should_panic attribute on the function to assert that the exception should be raised:

#[test]
#[should_panic]
fn should_error() {
  panic!("There should be a mistake.")}Copy the code

Make sure the exception thrown is expected and not an exception in another location:

#[test]
#[should_panic(expected = "Less than")]
fn should_error() {
  let a = 1;
  let b = 2;
  if a > b {
    panic!("A greater than b")}else {
    panic!("A less than b") // Expected 'less than' in this panic! The text in the}}Copy the code

Write tests using Result<T, E>, which can be used instead of the Assert series of tests that pass when the function returns Ok:

#[test]
fn use_result() - >Result< (),String> {
  let a = 1;
  let b = 1;
  if a == b {
    Result: :Ok(()) // The argument to Ok needs to be an empty tuple
  } else {
    Result: :Err(format!("{} != {}", a, b))
  }
}
Copy the code

Control how tests are run

Parameters for running tests:

cargo test --help
Copy the code

Controls how tests are run by separating command arguments with — :

cargo test -- --help
Copy the code

Cargo enables parallel testing by default to reduce test time. This means that multiple tests cannot depend on one another. You can use parameters to control the specific number of threads:

cargo test -- --test-threads=1
Copy the code

We can’t see println! In the code when the test passes. If Rust does not capture the annotation output, use the parameter to control Rust from capturing the annotation output:

cargo test -- --nocapture
Copy the code

You can reduce test time by running only part of the test cases, such as testing all test cases that match the string is_ :

cargo test is_
Copy the code

Run a single test:

cargo test it_works
Copy the code

Note: You cannot run multiple tests:

cargo test it_works is_eq
Copy the code

To omit certain tests by specifying them explicitly:

#[test]
#[ignore]
fn should_ignore() {
  panic!("This error will not be thrown because the should_ignore test will not be run.")}Copy the code

If you want to run only these ignored tests:

cargo test -- --ignored
Copy the code

Test organization structure

Unit testing

Unit tests are generally written in the same file as the business code, but are identified by creating a new test module:

pub fn add(a: i32, b: i32) - >i32 {
  a + b
}

// Modules marked as tests will be removed after cargo Build
// In addition, we do not need to tag integration tests with #[CFG (test)] because integration tests are placed in a separate directory and rust does not process them when building.
// CFG: configuration, which is processed only in test mode
#[cfg(test)]
mod testaaa {
  use super::add;
  #[test]
  pub fn test_add() {
    assert_eq!(add(1.2), 3)}}Copy the code

Integration testing

Integration tests are located entirely outside the SRC directory in the Tests folder:

mkdir tests
Copy the code

Test an external package adder:

use adder::add_one;
#[test]
fn test_add() {
  assert_eq!(add_one(1), 2)}Copy the code

Cargo tests (including unit tests, integration tests, document tests)

cargo test
Copy the code

Run only an integration test:

cargo test --test[Integration test file name]Copy the code

Integration test common functions need to be placed in the tests/common/mod.rs file, otherwise they will be identified as integration test cases by Rust elsewhere:

mod common; // References use public packages
#[test]
fn test_add() {
  // Use the setup function in the public package
  common::setup();
  assert_eq!(add_one(1), 2)}Copy the code