Rust6.1 Writing Automated Tests

Rust学习笔记

Rust编程语言入门教程课程笔记

参考教材: The Rust Programming Language (by Steve Klabnik and Carol Nichols, with contributions from the Rust Community)

Lecture 11: Writing Automated Tests

src/lib.rs

//Tests: Arrange, Act, Assert
//#[test] attribute tells the compiler to compile and run the code only when running tests

//cargo test --test-threads=1 //run tests in parallel or not
//cargo test -- --test-threads=1 //run tests in parallel or not

//Test Organization: Unit Tests, Integration Tests
//Unit Tests: tests for one module in isolation at a time
//Integration Tests: tests for multiple modules and how they work together

pub fn add(left: usize, right: usize) -> usize {
    left + right
}

pub fn add_two(a: i32) -> i32 {
    a + 2
}

#[derive(Debug)]
pub struct Rectangle {
    width: u32,
    height: u32,
}

impl Rectangle {
    pub fn can_hold(&self, other: &Rectangle) -> bool {
        // self.width > other.width && self.height > other.height
        self.width < other.width && self.height > other.height
    }
}

pub fn greeting(name: &str) -> String {
    format!("Hello {}!", name)
    //String::from("Hello!")
}

pub struct Guess {
    value: u32,
}

impl Guess {
    pub fn new(value: u32) -> Guess {
        // if value < 1 || value > 100 {
        //     panic!("Guess value must be between 1 and 100, got {}.", value);
        // }
        // Guess { value }
        if value < 1 {
            panic!(
                "Guess value must be greater than or equal to 1, got {}.",
                value
            );
        } else if value > 100 {
            panic!(
                "Guess value must be less than or equal to 100, got {}.",
                value
            );
        }
        Guess { value }
    }
}

fn prints_and_returns_10(a: i32) -> i32 {
    println!("I got the value {}", a);
    10
}

//Test Private Functions
pub fn add_three(a: i32) -> i32 {
    internal_adder(a, 3)
}

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

//Unit Tests
#[cfg(test)]//only compile and run the following code when we run cargo test (cfg = configuration)
mod tests {
    use super::*; //we have added use super::*;

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);// assert_eq: macro that compares two values for equality
        assert_ne!(result, 5);// assert_ne: macro that compares two values for inequality
        //If the two values are not equal, these macros will call panic and report the values 
    }

    #[test]
    fn it_works2() -> Result<(), String> {
        if add(2, 2) == 4 {
            Ok(())
        } else {
            Err(String::from("two plus two does not equal four"))
        }
        //The Result<(), String> type is a concrete type that implements the 
        //std::error::Error trait, which means we can use ? in the body of this test.
    }


    // #[test]
    // fn another() {
    //     panic!("Make this test fail");//panic! macro that comes with Rust
    // }

    #[test]
    fn larger_can_hold_smaller() {
        let larger = Rectangle {
            width: 10,
            height: 8,
        };
        let smaller = Rectangle {
            width: 5,
            height: 4,
        };
        // assert!(larger.can_hold(&smaller));
        assert!(!larger.can_hold(&smaller), "smaller can hold larger");
        //assert! with a custom failure message
    }

    #[test]
    fn greeting_contains_name() {
        let result = greeting("Carol");
        // assert!(result.contains("Carol"));
        assert!(
            result.contains("Carol"),
            "Greeting did not contain name, value was `{}`", result
        );
    }

    #[test]
    //#[should_panic]//#[should_panic] annotation on the test function
    #[should_panic(expected = "Guess value must be less than or equal to 100")]//#[should_panic] with expected
    fn greater_than_100() {
        Guess::new(200);
    }

    #[test]
    fn this_test_will_pass(){
        let value = prints_and_returns_10(4);
        assert_eq!(10, value);
        //cargo test -- --show-output
    }

    #[test]
    // fn this_test_will_fail(){
    //     let value = prints_and_returns_10(8);
    //     assert_eq!(5, value);
    //     //cargo test will output println! messages
    // }

    #[test]
    fn add_two_and_two(){
        assert_eq!(4, add_two(2));
    }

    #[test]
    fn add_three_and_two(){
        assert_eq!(5, add_two(3));
    }
    //cargo test add

    #[test]
    fn one_hundred(){
        assert_eq!(102, add_two(100));
    }
    //cargo test one_hundred

    #[test]
    #[ignore]
    fn expensive_test(){
        //code that takes an hour to run
        assert_eq!(1+1+1+1+1+1+1+1+1+1, 10);
    }
    //cargo test -- --ignored

    #[test]
    fn internal(){
        assert_eq!(5, internal_adder(2, 3));//internal_adder is private
    }

}

tests/integration_tests.rs

use adder;
mod common;

#[test]
fn it_adds_two() {
    common::setup();
    assert_eq!(4, adder::add_two(2));
}

//cargo test --test integration_tests

tests/another_integration_tests.rs

use adder;
mod common;
#[test]
fn it_really_adds_two() {
    common::setup();
    assert_eq!(4, adder::add_two(2));
}

tests/common/mod.rs

pub fn setup() {
    // setup code specific to your library's tests would go here
}

你可能感兴趣的:(rust,笔记)