]>
Commit | Line | Data |
---|---|---|
2c00a5a8 XL |
1 | # Unit testing |
2 | ||
3 | Tests are Rust functions that verify that the non-test code is functioning in | |
4 | the expected manner. The bodies of test functions typically perform some setup, | |
5 | run the code we want to test, then assert whether the results are what we | |
6 | expect. | |
7 | ||
8 | Most unit tests go into a `tests` [mod][mod] with the `#[cfg(test)]` [attribute][attribute]. | |
9 | Test functions are marked with the `#[test]` attribute. | |
10 | ||
11 | Tests fail when something in the test function [panics][panic]. There are some | |
12 | helper [macros][macros]: | |
13 | ||
14 | * `assert!(expression)` - panics if expression evaluates to `false`. | |
15 | * `assert_eq!(left, right)` and `assert_ne!(left, right)` - testing left and | |
16 | right expressions for equality and inequality respectively. | |
17 | ||
18 | ```rust,ignore | |
19 | pub fn add(a: i32, b: i32) -> i32 { | |
20 | a + b | |
21 | } | |
22 | ||
23 | // This is a really bad adding function, its purpose is to fail in this | |
24 | // example. | |
25 | #[allow(dead_code)] | |
26 | fn bad_add(a: i32, b: i32) -> i32 { | |
27 | a - b | |
28 | } | |
29 | ||
30 | #[cfg(test)] | |
31 | mod tests { | |
32 | // Note this useful idiom: importing names from outer (for mod tests) scope. | |
33 | use super::*; | |
34 | ||
35 | #[test] | |
36 | fn test_add() { | |
37 | assert_eq!(add(1, 2), 3); | |
38 | } | |
39 | ||
40 | #[test] | |
41 | fn test_bad_add() { | |
42 | // This assert would fire and test will fail. | |
43 | // Please note, that private functions can be tested too! | |
44 | assert_eq!(bad_add(1, 2), 3); | |
45 | } | |
46 | } | |
47 | ``` | |
48 | ||
49 | Tests can be run with `cargo test`. | |
50 | ||
416331ca | 51 | ```shell |
2c00a5a8 XL |
52 | $ cargo test |
53 | ||
54 | running 2 tests | |
55 | test tests::test_bad_add ... FAILED | |
56 | test tests::test_add ... ok | |
57 | ||
58 | failures: | |
59 | ||
60 | ---- tests::test_bad_add stdout ---- | |
61 | thread 'tests::test_bad_add' panicked at 'assertion failed: `(left == right)` | |
62 | left: `-1`, | |
63 | right: `3`', src/lib.rs:21:8 | |
64 | note: Run with `RUST_BACKTRACE=1` for a backtrace. | |
65 | ||
66 | ||
67 | failures: | |
68 | tests::test_bad_add | |
69 | ||
70 | test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out | |
71 | ``` | |
72 | ||
73 | ## Testing panics | |
74 | ||
75 | To check functions that should panic under certain circumstances, use attribute | |
76 | `#[should_panic]`. This attribute accepts optional parameter `expected = ` with | |
77 | the text of the panic message. If your function can panic in multiple ways, it helps | |
78 | make sure your test is testing the correct panic. | |
79 | ||
80 | ```rust,ignore | |
81 | pub fn divide_non_zero_result(a: u32, b: u32) -> u32 { | |
82 | if b == 0 { | |
83 | panic!("Divide-by-zero error"); | |
84 | } else if a < b { | |
85 | panic!("Divide result is zero"); | |
86 | } | |
87 | a / b | |
88 | } | |
89 | ||
90 | #[cfg(test)] | |
91 | mod tests { | |
92 | use super::*; | |
93 | ||
94 | #[test] | |
95 | fn test_divide() { | |
96 | assert_eq!(divide_non_zero_result(10, 2), 5); | |
97 | } | |
98 | ||
99 | #[test] | |
100 | #[should_panic] | |
101 | fn test_any_panic() { | |
102 | divide_non_zero_result(1, 0); | |
103 | } | |
104 | ||
105 | #[test] | |
106 | #[should_panic(expected = "Divide result is zero")] | |
107 | fn test_specific_panic() { | |
108 | divide_non_zero_result(1, 10); | |
109 | } | |
110 | } | |
111 | ``` | |
112 | ||
113 | Running these tests gives us: | |
114 | ||
416331ca | 115 | ```shell |
2c00a5a8 XL |
116 | $ cargo test |
117 | ||
118 | running 3 tests | |
119 | test tests::test_any_panic ... ok | |
120 | test tests::test_divide ... ok | |
121 | test tests::test_specific_panic ... ok | |
122 | ||
123 | test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out | |
124 | ||
125 | Doc-tests tmp-test-should-panic | |
126 | ||
127 | running 0 tests | |
128 | ||
129 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out | |
130 | ``` | |
131 | ||
132 | ## Running specific tests | |
133 | ||
134 | To run specific tests one may specify the test name to `cargo test` command. | |
135 | ||
416331ca | 136 | ```shell |
2c00a5a8 XL |
137 | $ cargo test test_any_panic |
138 | running 1 test | |
139 | test tests::test_any_panic ... ok | |
140 | ||
141 | test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out | |
142 | ||
143 | Doc-tests tmp-test-should-panic | |
144 | ||
145 | running 0 tests | |
146 | ||
147 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out | |
148 | ``` | |
149 | ||
150 | To run multiple tests one may specify part of a test name that matches all the | |
151 | tests that should be run. | |
152 | ||
416331ca | 153 | ```shell |
2c00a5a8 XL |
154 | $ cargo test panic |
155 | running 2 tests | |
156 | test tests::test_any_panic ... ok | |
157 | test tests::test_specific_panic ... ok | |
158 | ||
159 | test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out | |
160 | ||
161 | Doc-tests tmp-test-should-panic | |
162 | ||
163 | running 0 tests | |
164 | ||
165 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out | |
166 | ``` | |
167 | ||
168 | ## Ignoring tests | |
169 | ||
416331ca | 170 | Tests can be marked with the `#[ignore]` attribute to exclude some tests. Or to run |
2c00a5a8 XL |
171 | them with command `cargo test -- --ignored` |
172 | ||
173 | ```rust | |
174 | pub fn add(a: i32, b: i32) -> i32 { | |
175 | a + b | |
176 | } | |
177 | ||
178 | #[cfg(test)] | |
179 | mod tests { | |
180 | use super::*; | |
181 | ||
182 | #[test] | |
183 | fn test_add() { | |
184 | assert_eq!(add(2, 2), 4); | |
185 | } | |
186 | ||
187 | #[test] | |
188 | fn test_add_hundred() { | |
189 | assert_eq!(add(100, 2), 102); | |
190 | assert_eq!(add(2, 100), 102); | |
191 | } | |
192 | ||
193 | #[test] | |
194 | #[ignore] | |
195 | fn ignored_test() { | |
196 | assert_eq!(add(0, 0), 0); | |
197 | } | |
198 | } | |
199 | ``` | |
200 | ||
416331ca | 201 | ```shell |
2c00a5a8 | 202 | $ cargo test |
416331ca | 203 | running 3 tests |
2c00a5a8 | 204 | test tests::ignored_test ... ignored |
416331ca XL |
205 | test tests::test_add ... ok |
206 | test tests::test_add_hundred ... ok | |
2c00a5a8 | 207 | |
416331ca | 208 | test result: ok. 2 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out |
2c00a5a8 XL |
209 | |
210 | Doc-tests tmp-ignore | |
211 | ||
212 | running 0 tests | |
213 | ||
214 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out | |
215 | ||
216 | $ cargo test -- --ignored | |
217 | running 1 test | |
218 | test tests::ignored_test ... ok | |
219 | ||
220 | test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out | |
221 | ||
222 | Doc-tests tmp-ignore | |
223 | ||
224 | running 0 tests | |
225 | ||
226 | test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out | |
227 | ``` | |
228 | ||
dc9dc135 XL |
229 | [attribute]: ../attribute.md |
230 | [panic]: ../std/panic.md | |
231 | [macros]: ../macros.md | |
232 | [mod]: ../mod.md |