]> git.proxmox.com Git - rustc.git/blob - src/doc/book/src/ch11-01-writing-tests.md
New upstream version 1.63.0+dfsg1
[rustc.git] / src / doc / book / src / ch11-01-writing-tests.md
1 ## How to Write Tests
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 these three
5 actions:
6
7 1. Set up any needed data or state.
8 2. Run the code you want to test.
9 3. Assert the results are what you expect.
10
11 Let’s look at the features Rust provides specifically for writing tests that
12 take these actions, which include the `test` attribute, a few macros, and the
13 `should_panic` attribute.
14
15 ### The Anatomy of a Test Function
16
17 At its simplest, a test in Rust is a function that’s annotated with the `test`
18 attribute. Attributes are metadata about pieces of Rust code; one example is
19 the `derive` attribute we used with structs in Chapter 5. To change a function
20 into a test function, add `#[test]` on the line before `fn`. When you run your
21 tests with the `cargo test` command, Rust builds a test runner binary that runs
22 the annotated functions and reports on whether each
23 test function passes or fails.
24
25 Whenever we make a new library project with Cargo, a test module with a test
26 function in it is automatically generated for us. This module gives you a
27 template for writing your tests so you don’t have to look up the exact
28 structure and syntax every time you start a new project. You can add as many
29 additional test functions and as many test modules as you want!
30
31 We’ll explore some aspects of how tests work by experimenting with the template
32 test before we actually test any code. Then we’ll write some real-world tests
33 that call some code that we’ve written and assert that its behavior is correct.
34
35 Let’s create a new library project called `adder` that will add two numbers:
36
37 ```console
38 $ cargo new adder --lib
39 Created library `adder` project
40 $ cd adder
41 ```
42
43 The contents of the *src/lib.rs* file in your `adder` library should look like
44 Listing 11-1.
45
46 <span class="filename">Filename: src/lib.rs</span>
47
48 <!-- manual-regeneration
49 cd listings/ch11-writing-automated-tests
50 rm -rf listing-11-01
51 cargo new --lib listing-11-01 --name adder
52 cd listing-11-01
53 cargo test
54 git co output.txt
55 cd ../../..
56 -->
57
58 ```rust,noplayground
59 {{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-01/src/lib.rs}}
60 ```
61
62 <span class="caption">Listing 11-1: The test module and function generated
63 automatically by `cargo new`</span>
64
65 For now, let’s ignore the top two lines and focus on the function. Note the
66 `#[test]` annotation: this attribute indicates this is a test function, so the
67 test runner knows to treat this function as a test. We might also have non-test
68 functions in the `tests` module to help set up common scenarios or perform
69 common operations, so we always need to indicate which functions are tests.
70
71 The example function body uses the `assert_eq!` macro to assert that `result`,
72 which contains the result of adding 2 and 2, equals 4. This assertion serves as
73 an example of the format for a typical test. Let’s run it to see that this test
74 passes.
75
76 The `cargo test` command runs all tests in our project, as shown in Listing
77 11-2.
78
79 ```console
80 {{#include ../listings/ch11-writing-automated-tests/listing-11-01/output.txt}}
81 ```
82
83 <span class="caption">Listing 11-2: The output from running the automatically
84 generated test</span>
85
86 Cargo compiled and ran the test. We see the line `running 1 test`. The next
87 line shows the name of the generated test function, called `it_works`, and that
88 the result of running that test is `ok`. The overall summary `test result: ok.`
89 means that all the tests passed, and the portion that reads `1 passed; 0
90 failed` totals the number of tests that passed or failed.
91
92 It’s possible to mark a test as ignored so it doesn’t run in a particular
93 instance; we’ll cover that in the [“Ignoring Some Tests Unless Specifically
94 Requested”][ignoring]<!-- ignore --> section later in this chapter. Because we
95 haven’t done that here, the summary shows `0 ignored`. We can also pass an
96 argument to the `cargo test` command to run only tests whose name matches a
97 string; this is called *filtering* and we’ll cover that in the [“Running a
98 Subset of Tests by Name”][subset]<!-- ignore --> section. We also haven’t
99 filtered the tests being run, so the end of the summary shows `0 filtered out`.
100
101 The `0 measured` statistic is for benchmark tests that measure performance.
102 Benchmark tests are, as of this writing, only available in nightly Rust. See
103 [the documentation about benchmark tests][bench] to learn more.
104
105 The next part of the test output starting at `Doc-tests adder` is for the
106 results of any documentation tests. We don’t have any documentation tests yet,
107 but Rust can compile any code examples that appear in our API documentation.
108 This feature helps keep your docs and your code in sync! We’ll discuss how to
109 write documentation tests in the [“Documentation Comments as
110 Tests”][doc-comments]<!-- ignore --> section of Chapter 14. For now, we’ll
111 ignore the `Doc-tests` output.
112
113 Let’s start to customize the test to our own needs. First change the name of
114 the `it_works` function to a different name, such as `exploration`, like so:
115
116 <span class="filename">Filename: src/lib.rs</span>
117
118 ```rust,noplayground
119 {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/src/lib.rs}}
120 ```
121
122 Then run `cargo test` again. The output now shows `exploration` instead of
123 `it_works`:
124
125 ```console
126 {{#include ../listings/ch11-writing-automated-tests/no-listing-01-changing-test-name/output.txt}}
127 ```
128
129 Now we’ll add another test, but this time we’ll make a test that fails! Tests
130 fail when something in the test function panics. Each test is run in a new
131 thread, and when the main thread sees that a test thread has died, the test is
132 marked as failed. In Chapter 9, we talked about how the simplest way to panic
133 is to call the `panic!` macro. Enter the new test as a function named
134 `another`, so your *src/lib.rs* file looks like Listing 11-3.
135
136 <span class="filename">Filename: src/lib.rs</span>
137
138 ```rust,panics,noplayground
139 {{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-03/src/lib.rs:here}}
140 ```
141
142 <span class="caption">Listing 11-3: Adding a second test that will fail because
143 we call the `panic!` macro</span>
144
145 Run the tests again using `cargo test`. The output should look like Listing
146 11-4, which shows that our `exploration` test passed and `another` failed.
147
148 ```console
149 {{#include ../listings/ch11-writing-automated-tests/listing-11-03/output.txt}}
150 ```
151
152 <span class="caption">Listing 11-4: Test results when one test passes and one
153 test fails</span>
154
155 Instead of `ok`, the line `test tests::another` shows `FAILED`. Two new
156 sections appear between the individual results and the summary: the first
157 displays the detailed reason for each test failure. In this case, we get the
158 details that `another` failed because it `panicked at 'Make this test fail'` on
159 line 10 in the *src/lib.rs* file. The next section lists just the names of all
160 the failing tests, which is useful when there are lots of tests and lots of
161 detailed failing test output. We can use the name of a failing test to run just
162 that test to more easily debug it; we’ll talk more about ways to run tests in
163 the [“Controlling How Tests Are Run”][controlling-how-tests-are-run]<!-- ignore
164 --> section.
165
166 The summary line displays at the end: overall, our test result is `FAILED`. We
167 had one test pass and one test fail.
168
169 Now that you’ve seen what the test results look like in different scenarios,
170 let’s look at some macros other than `panic!` that are useful in tests.
171
172 ### Checking Results with the `assert!` Macro
173
174 The `assert!` macro, provided by the standard library, is useful when you want
175 to ensure that some condition in a test evaluates to `true`. We give the
176 `assert!` macro an argument that evaluates to a Boolean. If the value is
177 `true`, nothing happens and the test passes. If the value is `false`, the
178 `assert!` macro calls `panic!` to cause the test to fail. Using the `assert!`
179 macro helps us check that our code is functioning in the way we intend.
180
181 In Chapter 5, Listing 5-15, we used a `Rectangle` struct and a `can_hold`
182 method, which are repeated here in Listing 11-5. Let’s put this code in the
183 *src/lib.rs* file, then write some tests for it using the `assert!` macro.
184
185 <span class="filename">Filename: src/lib.rs</span>
186
187 ```rust,noplayground
188 {{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-05/src/lib.rs:here}}
189 ```
190
191 <span class="caption">Listing 11-5: Using the `Rectangle` struct and its
192 `can_hold` method from Chapter 5</span>
193
194 The `can_hold` method returns a Boolean, which means it’s a perfect use case
195 for the `assert!` macro. In Listing 11-6, we write a test that exercises the
196 `can_hold` method by creating a `Rectangle` instance that has a width of 8 and
197 a height of 7 and asserting that it can hold another `Rectangle` instance that
198 has a width of 5 and a height of 1.
199
200 <span class="filename">Filename: src/lib.rs</span>
201
202 ```rust,noplayground
203 {{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-06/src/lib.rs:here}}
204 ```
205
206 <span class="caption">Listing 11-6: A test for `can_hold` that checks whether a
207 larger rectangle can indeed hold a smaller rectangle</span>
208
209 Note that we’ve added a new line inside the `tests` module: `use super::*;`.
210 The `tests` module is a regular module that follows the usual visibility rules
211 we covered in Chapter 7 in the [“Paths for Referring to an Item in the Module
212 Tree”][paths-for-referring-to-an-item-in-the-module-tree]<!-- ignore -->
213 section. Because the `tests` module is an inner module, we need to bring the
214 code under test in the outer module into the scope of the inner module. We use
215 a glob here so anything we define in the outer module is available to this
216 `tests` module.
217
218 We’ve named our test `larger_can_hold_smaller`, and we’ve created the two
219 `Rectangle` instances that we need. Then we called the `assert!` macro and
220 passed it the result of calling `larger.can_hold(&smaller)`. This expression is
221 supposed to return `true`, so our test should pass. Let’s find out!
222
223 ```console
224 {{#include ../listings/ch11-writing-automated-tests/listing-11-06/output.txt}}
225 ```
226
227 It does pass! Let’s add another test, this time asserting that a smaller
228 rectangle cannot hold a larger rectangle:
229
230 <span class="filename">Filename: src/lib.rs</span>
231
232 ```rust,noplayground
233 {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/src/lib.rs:here}}
234 ```
235
236 Because the correct result of the `can_hold` function in this case is `false`,
237 we need to negate that result before we pass it to the `assert!` macro. As a
238 result, our test will pass if `can_hold` returns `false`:
239
240 ```console
241 {{#include ../listings/ch11-writing-automated-tests/no-listing-02-adding-another-rectangle-test/output.txt}}
242 ```
243
244 Two tests that pass! Now let’s see what happens to our test results when we
245 introduce a bug in our code. We’ll change the implementation of the `can_hold`
246 method by replacing the greater-than sign with a less-than sign when it
247 compares the widths:
248
249 ```rust,not_desired_behavior,noplayground
250 {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/src/lib.rs:here}}
251 ```
252
253 Running the tests now produces the following:
254
255 ```console
256 {{#include ../listings/ch11-writing-automated-tests/no-listing-03-introducing-a-bug/output.txt}}
257 ```
258
259 Our tests caught the bug! Because `larger.width` is 8 and `smaller.width` is
260 5, the comparison of the widths in `can_hold` now returns `false`: 8 is not
261 less than 5.
262
263 ### Testing Equality with the `assert_eq!` and `assert_ne!` Macros
264
265 A common way to verify functionality is to test for equality between the result
266 of the code under test and the value you expect the code to return. You could
267 do this using the `assert!` macro and passing it an expression using the `==`
268 operator. However, this is such a common test that the standard library
269 provides a pair of macros—`assert_eq!` and `assert_ne!`—to perform this test
270 more conveniently. These macros compare two arguments for equality or
271 inequality, respectively. They’ll also print the two values if the assertion
272 fails, which makes it easier to see *why* the test failed; conversely, the
273 `assert!` macro only indicates that it got a `false` value for the `==`
274 expression, without printing the values that led to the `false` value.
275
276 In Listing 11-7, we write a function named `add_two` that adds `2` to its
277 parameter, then we test this function using the `assert_eq!` macro.
278
279 <span class="filename">Filename: src/lib.rs</span>
280
281 ```rust,noplayground
282 {{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-07/src/lib.rs}}
283 ```
284
285 <span class="caption">Listing 11-7: Testing the function `add_two` using the
286 `assert_eq!` macro</span>
287
288 Let’s check that it passes!
289
290 ```console
291 {{#include ../listings/ch11-writing-automated-tests/listing-11-07/output.txt}}
292 ```
293
294 We pass `4` as the argument to `assert_eq!`, which is equal to the result of
295 calling `add_two(2)`. The line for this test is `test tests::it_adds_two ...
296 ok`, and the `ok` text indicates that our test passed!
297
298 Let’s introduce a bug into our code to see what `assert_eq!` looks like when it
299 fails. Change the implementation of the `add_two` function to instead add `3`:
300
301 ```rust,not_desired_behavior,noplayground
302 {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/src/lib.rs:here}}
303 ```
304
305 Run the tests again:
306
307 ```console
308 {{#include ../listings/ch11-writing-automated-tests/no-listing-04-bug-in-add-two/output.txt}}
309 ```
310
311 Our test caught the bug! The `it_adds_two` test failed, and the message tells
312 us that the assertion that fails was `` assertion failed: `(left == right)` ``
313 and what the `left` and `right` values are. This message helps us start
314 debugging: the `left` argument was `4` but the `right` argument, where we had
315 `add_two(2)`, was `5`. You can imagine that this would be especially helpful
316 when we have a lot of tests going on.
317
318 Note that in some languages and test frameworks, the parameters to equality
319 assertion functions are called `expected` and `actual`, and the order in which
320 we specify the arguments matters. However, in Rust, they’re called `left` and
321 `right`, and the order in which we specify the value we expect and the value
322 the code produces doesn’t matter. We could write the assertion in this test as
323 `assert_eq!(add_two(2), 4)`, which would result in the same failure message
324 that displays `` assertion failed: `(left == right)` ``.
325
326 The `assert_ne!` macro will pass if the two values we give it are not equal and
327 fail if they’re equal. This macro is most useful for cases when we’re not sure
328 what a value *will* be, but we know what the value definitely *shouldn’t* be.
329 For example, if we’re testing a function that is guaranteed to change its input
330 in some way, but the way in which the input is changed depends on the day of
331 the week that we run our tests, the best thing to assert might be that the
332 output of the function is not equal to the input.
333
334 Under the surface, the `assert_eq!` and `assert_ne!` macros use the operators
335 `==` and `!=`, respectively. When the assertions fail, these macros print their
336 arguments using debug formatting, which means the values being compared must
337 implement the `PartialEq` and `Debug` traits. All primitive types and most of
338 the standard library types implement these traits. For structs and enums that
339 you define yourself, you’ll need to implement `PartialEq` to assert equality of
340 those types. You’ll also need to implement `Debug` to print the values when the
341 assertion fails. Because both traits are derivable traits, as mentioned in
342 Listing 5-12 in Chapter 5, this is usually as straightforward as adding the
343 `#[derive(PartialEq, Debug)]` annotation to your struct or enum definition. See
344 Appendix C, [“Derivable Traits,”][derivable-traits]<!-- ignore --> for more
345 details about these and other derivable traits.
346
347 ### Adding Custom Failure Messages
348
349 You can also add a custom message to be printed with the failure message as
350 optional arguments to the `assert!`, `assert_eq!`, and `assert_ne!` macros. Any
351 arguments specified after the required arguments are passed along to the
352 `format!` macro (discussed in Chapter 8 in the [“Concatenation with the `+`
353 Operator or the `format!`
354 Macro”][concatenation-with-the--operator-or-the-format-macro]<!-- ignore -->
355 section), so you can pass a format string that contains `{}` placeholders and
356 values to go in those placeholders. Custom messages are useful for documenting
357 what an assertion means; when a test fails, you’ll have a better idea of what
358 the problem is with the code.
359
360 For example, let’s say we have a function that greets people by name and we
361 want to test that the name we pass into the function appears in the output:
362
363 <span class="filename">Filename: src/lib.rs</span>
364
365 ```rust,noplayground
366 {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-05-greeter/src/lib.rs}}
367 ```
368
369 The requirements for this program haven’t been agreed upon yet, and we’re
370 pretty sure the `Hello` text at the beginning of the greeting will change. We
371 decided we don’t want to have to update the test when the requirements change,
372 so instead of checking for exact equality to the value returned from the
373 `greeting` function, we’ll just assert that the output contains the text of the
374 input parameter.
375
376 Now let’s introduce a bug into this code by changing `greeting` to exclude
377 `name` to see what the default test failure looks like:
378
379 ```rust,not_desired_behavior,noplayground
380 {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/src/lib.rs:here}}
381 ```
382
383 Running this test produces the following:
384
385 ```console
386 {{#include ../listings/ch11-writing-automated-tests/no-listing-06-greeter-with-bug/output.txt}}
387 ```
388
389 This result just indicates that the assertion failed and which line the
390 assertion is on. A more useful failure message would print the value from the
391 `greeting` function. Let’s add a custom failure message composed of a format
392 string with a placeholder filled in with the actual value we got from the
393 `greeting` function:
394
395 ```rust,ignore
396 {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/src/lib.rs:here}}
397 ```
398
399 Now when we run the test, we’ll get a more informative error message:
400
401 ```console
402 {{#include ../listings/ch11-writing-automated-tests/no-listing-07-custom-failure-message/output.txt}}
403 ```
404
405 We can see the value we actually got in the test output, which would help us
406 debug what happened instead of what we were expecting to happen.
407
408 ### Checking for Panics with `should_panic`
409
410 In addition to checking return values, it’s important to check that our code
411 handles error conditions as we expect. For example, consider the `Guess` type
412 that we created in Chapter 9, Listing 9-13. Other code that uses `Guess`
413 depends on the guarantee that `Guess` instances will contain only values
414 between 1 and 100. We can write a test that ensures that attempting to create a
415 `Guess` instance with a value outside that range panics.
416
417 We do this by adding the attribute `should_panic` to our test function. The
418 test passes if the code inside the function panics; the test fails if the code
419 inside the function doesn’t panic.
420
421 Listing 11-8 shows a test that checks that the error conditions of `Guess::new`
422 happen when we expect them to.
423
424 <span class="filename">Filename: src/lib.rs</span>
425
426 ```rust,noplayground
427 {{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-08/src/lib.rs}}
428 ```
429
430 <span class="caption">Listing 11-8: Testing that a condition will cause a
431 `panic!`</span>
432
433 We place the `#[should_panic]` attribute after the `#[test]` attribute and
434 before the test function it applies to. Let’s look at the result when this test
435 passes:
436
437 ```console
438 {{#include ../listings/ch11-writing-automated-tests/listing-11-08/output.txt}}
439 ```
440
441 Looks good! Now let’s introduce a bug in our code by removing the condition
442 that the `new` function will panic if the value is greater than 100:
443
444 ```rust,not_desired_behavior,noplayground
445 {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/src/lib.rs:here}}
446 ```
447
448 When we run the test in Listing 11-8, it will fail:
449
450 ```console
451 {{#include ../listings/ch11-writing-automated-tests/no-listing-08-guess-with-bug/output.txt}}
452 ```
453
454 We don’t get a very helpful message in this case, but when we look at the test
455 function, we see that it’s annotated with `#[should_panic]`. The failure we got
456 means that the code in the test function did not cause a panic.
457
458 Tests that use `should_panic` can be imprecise. A `should_panic` test would
459 pass even if the test panics for a different reason from the one we were
460 expecting. To make `should_panic` tests more precise, we can add an optional
461 `expected` parameter to the `should_panic` attribute. The test harness will
462 make sure that the failure message contains the provided text. For example,
463 consider the modified code for `Guess` in Listing 11-9 where the `new` function
464 panics with different messages depending on whether the value is too small or
465 too large.
466
467 <span class="filename">Filename: src/lib.rs</span>
468
469 ```rust,noplayground
470 {{#rustdoc_include ../listings/ch11-writing-automated-tests/listing-11-09/src/lib.rs:here}}
471 ```
472
473 <span class="caption">Listing 11-9: Testing for a `panic!` with a panic message
474 containing a specified substring</span>
475
476 This test will pass because the value we put in the `should_panic` attribute’s
477 `expected` parameter is a substring of the message that the `Guess::new`
478 function panics with. We could have specified the entire panic message that we
479 expect, which in this case would be `Guess value must be less than or equal to
480 100, got 200.` What you choose to specify depends on how much of the panic
481 message is unique or dynamic and how precise you want your test to be. In this
482 case, a substring of the panic message is enough to ensure that the code in the
483 test function executes the `else if value > 100` case.
484
485 To see what happens when a `should_panic` test with an `expected` message
486 fails, let’s again introduce a bug into our code by swapping the bodies of the
487 `if value < 1` and the `else if value > 100` blocks:
488
489 ```rust,ignore,not_desired_behavior
490 {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/src/lib.rs:here}}
491 ```
492
493 This time when we run the `should_panic` test, it will fail:
494
495 ```console
496 {{#include ../listings/ch11-writing-automated-tests/no-listing-09-guess-with-panic-msg-bug/output.txt}}
497 ```
498
499 The failure message indicates that this test did indeed panic as we expected,
500 but the panic message did not include the expected string `'Guess value must be
501 less than or equal to 100'`. The panic message that we did get in this case was
502 `Guess value must be greater than or equal to 1, got 200.` Now we can start
503 figuring out where our bug is!
504
505 ### Using `Result<T, E>` in Tests
506
507 Our tests so far all panic when they fail. We can also write tests that use
508 `Result<T, E>`! Here’s the test from Listing 11-1, rewritten to use `Result<T,
509 E>` and return an `Err` instead of panicking:
510
511 ```rust,noplayground
512 {{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs}}
513 ```
514
515 The `it_works` function now has the `Result<(), String>` return type. In the
516 body of the function, rather than calling the `assert_eq!` macro, we return
517 `Ok(())` when the test passes and an `Err` with a `String` inside when the test
518 fails.
519
520 Writing tests so they return a `Result<T, E>` enables you to use the question
521 mark operator in the body of tests, which can be a convenient way to write
522 tests that should fail if any operation within them returns an `Err` variant.
523
524 You can’t use the `#[should_panic]` annotation on tests that use `Result<T,
525 E>`. To assert that an operation returns an `Err` variant, *don’t* use the
526 question mark operator on the `Result<T, E>` value. Instead, use
527 `assert!(value.is_err())`.
528
529 Now that you know several ways to write tests, let’s look at what is happening
530 when we run our tests and explore the different options we can use with `cargo
531 test`.
532
533 [concatenation-with-the--operator-or-the-format-macro]:
534 ch08-02-strings.html#concatenation-with-the--operator-or-the-format-macro
535 [bench]: ../unstable-book/library-features/test.html
536 [ignoring]: ch11-02-running-tests.html#ignoring-some-tests-unless-specifically-requested
537 [subset]: ch11-02-running-tests.html#running-a-subset-of-tests-by-name
538 [controlling-how-tests-are-run]:
539 ch11-02-running-tests.html#controlling-how-tests-are-run
540 [derivable-traits]: appendix-03-derivable-traits.html
541 [doc-comments]: ch14-02-publishing-to-crates-io.html#documentation-comments-as-tests
542 [paths-for-referring-to-an-item-in-the-module-tree]: ch07-03-paths-for-referring-to-an-item-in-the-module-tree.html