]> git.proxmox.com Git - rustc.git/blame - src/doc/trpl/testing.md
Imported Upstream version 1.0.0~beta
[rustc.git] / src / doc / trpl / testing.md
CommitLineData
85aaf69f 1% Testing
1a4d82fc
JJ
2
3> Program testing can be a very effective way to show the presence of bugs, but
c34b1796 4> it is hopelessly inadequate for showing their absence.
1a4d82fc
JJ
5>
6> Edsger W. Dijkstra, "The Humble Programmer" (1972)
7
8Let's talk about how to test Rust code. What we will not be talking about is
9the right way to test Rust code. There are many schools of thought regarding
10the right and wrong way to write tests. All of these approaches use the same
11basic tools, and so we'll show you the syntax for using them.
12
13# The `test` attribute
14
15At its simplest, a test in Rust is a function that's annotated with the `test`
16attribute. Let's make a new project with Cargo called `adder`:
17
18```bash
19$ cargo new adder
20$ cd adder
21```
22
23Cargo will automatically generate a simple test when you make a new project.
24Here's the contents of `src/lib.rs`:
25
26```rust
27#[test]
28fn it_works() {
29}
30```
31
32Note the `#[test]`. This attribute indicates that this is a test function. It
33currently has no body. That's good enough to pass! We can run the tests with
34`cargo test`:
35
36```bash
37$ cargo test
38 Compiling adder v0.0.1 (file:///home/you/projects/adder)
39 Running target/adder-91b3e234d4ed382a
40
41running 1 test
42test it_works ... ok
43
44test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
45
46 Doc-tests adder
47
48running 0 tests
49
50test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
51```
52
53Cargo compiled and ran our tests. There are two sets of output here: one
54for the test we wrote, and another for documentation tests. We'll talk about
55those later. For now, see this line:
56
57```text
58test it_works ... ok
59```
60
61Note the `it_works`. This comes from the name of our function:
62
63```rust
64fn it_works() {
65# }
66```
67
68We also get a summary line:
69
70```text
71test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
72```
73
74So why does our do-nothing test pass? Any test which doesn't `panic!` passes,
75and any test that does `panic!` fails. Let's make our test fail:
76
77```rust
78#[test]
79fn it_works() {
80 assert!(false);
81}
82```
83
84`assert!` is a macro provided by Rust which takes one argument: if the argument
85is `true`, nothing happens. If the argument is false, it `panic!`s. Let's run
86our tests again:
87
88```bash
89$ cargo test
90 Compiling adder v0.0.1 (file:///home/you/projects/adder)
91 Running target/adder-91b3e234d4ed382a
92
93running 1 test
94test it_works ... FAILED
95
96failures:
97
98---- it_works stdout ----
85aaf69f 99 thread 'it_works' panicked at 'assertion failed: false', /home/steve/tmp/adder/src/lib.rs:3
1a4d82fc
JJ
100
101
102
103failures:
104 it_works
105
106test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
107
85aaf69f 108thread '<main>' panicked at 'Some tests failed', /home/steve/src/rust/src/libtest/lib.rs:247
1a4d82fc
JJ
109```
110
111Rust indicates that our test failed:
112
113```text
114test it_works ... FAILED
115```
116
117And that's reflected in the summary line:
118
119```text
120test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
121```
122
123We also get a non-zero status code:
124
125```bash
126$ echo $?
127101
128```
129
130This is useful if you want to integrate `cargo test` into other tooling.
131
c34b1796 132We can invert our test's failure with another attribute: `should_panic`:
1a4d82fc
JJ
133
134```rust
135#[test]
c34b1796 136#[should_panic]
1a4d82fc
JJ
137fn it_works() {
138 assert!(false);
139}
140```
141
142This test will now succeed if we `panic!` and fail if we complete. Let's try it:
143
144```bash
145$ cargo test
146 Compiling adder v0.0.1 (file:///home/you/projects/adder)
147 Running target/adder-91b3e234d4ed382a
148
149running 1 test
150test it_works ... ok
151
152test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
153
154 Doc-tests adder
155
156running 0 tests
157
158test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
159```
160
161Rust provides another macro, `assert_eq!`, that compares two arguments for
162equality:
163
164```rust
165#[test]
c34b1796 166#[should_panic]
1a4d82fc
JJ
167fn it_works() {
168 assert_eq!("Hello", "world");
169}
170```
171
c34b1796 172Does this test pass or fail? Because of the `should_panic` attribute, it
1a4d82fc
JJ
173passes:
174
175```bash
176$ cargo test
177 Compiling adder v0.0.1 (file:///home/you/projects/adder)
178 Running target/adder-91b3e234d4ed382a
179
180running 1 test
181test it_works ... ok
182
183test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
184
185 Doc-tests adder
186
187running 0 tests
188
189test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
190```
191
c34b1796 192`should_panic` tests can be fragile, as it's hard to guarantee that the test
1a4d82fc 193didn't fail for an unexpected reason. To help with this, an optional `expected`
c34b1796 194parameter can be added to the `should_panic` attribute. The test harness will
1a4d82fc
JJ
195make sure that the failure message contains the provided text. A safer version
196of the example above would be:
197
198```
199#[test]
c34b1796 200#[should_panic(expected = "assertion failed")]
1a4d82fc
JJ
201fn it_works() {
202 assert_eq!("Hello", "world");
203}
204```
205
206That's all there is to the basics! Let's write one 'real' test:
207
208```{rust,ignore}
209pub fn add_two(a: i32) -> i32 {
210 a + 2
211}
212
213#[test]
214fn it_works() {
215 assert_eq!(4, add_two(2));
216}
217```
218
219This is a very common use of `assert_eq!`: call some function with
220some known arguments and compare it to the expected output.
221
222# The `test` module
223
224There is one way in which our existing example is not idiomatic: it's
225missing the test module. The idiomatic way of writing our example
226looks like this:
227
228```{rust,ignore}
229pub fn add_two(a: i32) -> i32 {
230 a + 2
231}
232
233#[cfg(test)]
c34b1796 234mod test {
1a4d82fc
JJ
235 use super::add_two;
236
237 #[test]
238 fn it_works() {
239 assert_eq!(4, add_two(2));
240 }
241}
242```
243
c34b1796 244There's a few changes here. The first is the introduction of a `mod test` with
1a4d82fc
JJ
245a `cfg` attribute. The module allows us to group all of our tests together, and
246to also define helper functions if needed, that don't become a part of the rest
247of our crate. The `cfg` attribute only compiles our test code if we're
248currently trying to run the tests. This can save compile time, and also ensures
249that our tests are entirely left out of a normal build.
250
251The second change is the `use` declaration. Because we're in an inner module,
252we need to bring our test function into scope. This can be annoying if you have
253a large module, and so this is a common use of the `glob` feature. Let's change
254our `src/lib.rs` to make use of it:
255
256```{rust,ignore}
1a4d82fc
JJ
257
258pub fn add_two(a: i32) -> i32 {
259 a + 2
260}
261
262#[cfg(test)]
c34b1796 263mod test {
1a4d82fc
JJ
264 use super::*;
265
266 #[test]
267 fn it_works() {
268 assert_eq!(4, add_two(2));
269 }
270}
271```
272
85aaf69f 273Note the different `use` line. Now we run our tests:
1a4d82fc
JJ
274
275```bash
276$ cargo test
277 Updating registry `https://github.com/rust-lang/crates.io-index`
278 Compiling adder v0.0.1 (file:///home/you/projects/adder)
279 Running target/adder-91b3e234d4ed382a
280
281running 1 test
282test test::it_works ... ok
283
284test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
285
286 Doc-tests adder
287
288running 0 tests
289
290test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
291```
292
293It works!
294
85aaf69f 295The current convention is to use the `test` module to hold your "unit-style"
1a4d82fc 296tests. Anything that just tests one small bit of functionality makes sense to
85aaf69f 297go here. But what about "integration-style" tests instead? For that, we have
1a4d82fc
JJ
298the `tests` directory
299
300# The `tests` directory
301
302To write an integration test, let's make a `tests` directory, and
303put a `tests/lib.rs` file inside, with this as its contents:
304
305```{rust,ignore}
306extern crate adder;
307
308#[test]
309fn it_works() {
85aaf69f 310 assert_eq!(4, adder::add_two(2));
c34b1796 311}
1a4d82fc
JJ
312```
313
314This looks similar to our previous tests, but slightly different. We now have
315an `extern crate adder` at the top. This is because the tests in the `tests`
316directory are an entirely separate crate, and so we need to import our library.
317This is also why `tests` is a suitable place to write integration-style tests:
318they use the library like any other consumer of it would.
319
320Let's run them:
321
322```bash
323$ cargo test
324 Compiling adder v0.0.1 (file:///home/you/projects/adder)
325 Running target/adder-91b3e234d4ed382a
326
327running 1 test
328test test::it_works ... ok
329
330test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
331
332 Running target/lib-c18e7d3494509e74
333
334running 1 test
335test it_works ... ok
336
337test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
338
339 Doc-tests adder
340
341running 0 tests
342
343test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
344```
345
346Now we have three sections: our previous test is also run, as well as our new
347one.
348
349That's all there is to the `tests` directory. The `test` module isn't needed
350here, since the whole thing is focused on tests.
351
352Let's finally check out that third section: documentation tests.
353
354# Documentation tests
355
356Nothing is better than documentation with examples. Nothing is worse than
357examples that don't actually work, because the code has changed since the
358documentation has been written. To this end, Rust supports automatically
359running examples in your documentation. Here's a fleshed-out `src/lib.rs`
360with examples:
361
362```{rust,ignore}
363//! The `adder` crate provides functions that add numbers to other numbers.
364//!
365//! # Examples
366//!
367//! ```
368//! assert_eq!(4, adder::add_two(2));
369//! ```
370
1a4d82fc
JJ
371/// This function adds two to its argument.
372///
373/// # Examples
374///
375/// ```
376/// use adder::add_two;
377///
378/// assert_eq!(4, add_two(2));
379/// ```
380pub fn add_two(a: i32) -> i32 {
381 a + 2
382}
383
384#[cfg(test)]
385mod tests {
386 use super::*;
387
388 #[test]
389 fn it_works() {
390 assert_eq!(4, add_two(2));
391 }
392}
393```
394
395Note the module-level documentation with `//!` and the function-level
396documentation with `///`. Rust's documentation supports Markdown in comments,
397and so triple graves mark code blocks. It is conventional to include the
398`# Examples` section, exactly like that, with examples following.
399
400Let's run the tests again:
401
402```bash
403$ cargo test
404 Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
405 Running target/adder-91b3e234d4ed382a
406
407running 1 test
408test test::it_works ... ok
409
410test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
411
412 Running target/lib-c18e7d3494509e74
413
414running 1 test
415test it_works ... ok
416
417test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
418
419 Doc-tests adder
420
421running 2 tests
422test add_two_0 ... ok
423test _0 ... ok
424
425test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured
426```
427
428Now we have all three kinds of tests running! Note the names of the
429documentation tests: the `_0` is generated for the module test, and `add_two_0`
430for the function test. These will auto increment with names like `add_two_1` as
431you add more examples.
432