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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
//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

1
2
3
4
5
6
7
8
9
10
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

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

tests/common/mod.rs

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