]> git.proxmox.com Git - rustc.git/blame - src/doc/book/second-edition/src/ch11-01-writing-tests.md
New upstream version 1.19.0+dfsg1
[rustc.git] / src / doc / book / second-edition / src / ch11-01-writing-tests.md
CommitLineData
cc61c64b
XL
1## How to Write Tests
2
3Tests are Rust functions that verify non-test code is functioning in the
4program in the expected manner. The bodies of test functions typically contain
5some setup, running the code we want to test, then asserting that the results
6are what we expect. Let's look at the features Rust provides specifically for
7writing tests: the `test` attribute, a few macros, and the `should_panic`
8attribute.
9
10### The Anatomy of a Test Function
11
12At its simplest, a test in Rust is a function that's annotated with the `test`
13attribute. Attributes are metadata about pieces of Rust code: the `derive`
14attribute that we used with structs in Chapter 5 is one example. To make a
15function into a test function, we add `#[test]` on the line before `fn`. When
16we run our tests with the `cargo test` command, Rust will build a test runner
17binary that runs the functions annotated with the `test` attribute and reports
18on whether each test function passes or fails.
19
20<!-- is it annotated with `test` by the user, or only automatically? I think
21it's the latter, and has edited with a more active tone to make that clear, but
22please change if I'm wrong -->
23<!-- What do you mean by "only automatically"? The reader should be typing in
24`#[test] on their own when they add new test functions; there's nothing special
25about that text. I'm not sure what part of this chapter implied "only
26automatically", can you point out where that's happening if we haven't taken
27care of it? /Carol -->
28
29We saw in Chapter 7 that when you make a new library project with Cargo, a test
30module with a test function in it is automatically generated for us. This is to
31help us get started writing our tests, since we don't have to go look up the
32exact structure and syntax of test functions every time we start a new project.
33We can add as many additional test functions and as many test modules as we
34want, though!
35
36We're going to explore some aspects of how tests work by experimenting with the
37template test generated for us, without actually testing any code. Then we'll
38write some real-world tests that call some code that we've written and assert
39that its behavior is correct.
40
41Let's create a new library project called `adder`:
42
43```text
44$ cargo new adder
45 Created library `adder` project
46$ cd adder
47```
48
49The contents of the `src/lib.rs` file in your adder library should be as
50follows:
51
52<span class="filename">Filename: src/lib.rs</span>
53
54```rust
55#[cfg(test)]
56mod tests {
57 #[test]
58 fn it_works() {
59 }
60}
61```
62
63<span class="caption">Listing 11-1: The test module and function generated
64automatically for us by `cargo new` </span>
65
66For now, let's ignore the top two lines and focus on the function to see how it
67works. Note the `#[test]` annotation before the `fn` line: this attribute
68indicates this is a test function, so that the test runner knows to treat this
69function as a test. We could also have non-test functions in the `tests` module
70to help set up common scenarios or perform common operations, so we need to
71indicate which functions are tests with the `#[test]` attribute.
72
73The function currently has no body, which means there is no code to fail the
74test; an empty test is a passing test! Let's run it and see that this test
75passes.
76
77The `cargo test` command runs all tests we have in our project, as shown in
78Listing 11-2:
79
80```text
81$ cargo test
82 Compiling adder v0.1.0 (file:///projects/adder)
7cac9316 83 Finished dev [unoptimized + debuginfo] target(s) in 0.22 secs
cc61c64b
XL
84 Running target/debug/deps/adder-ce99bcc2479f4607
85
86running 1 test
87test tests::it_works ... ok
88
89test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
90
91 Doc-tests adder
92
93running 0 tests
94
95test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
96```
97
98<span class="caption">Listing 11-2: The output from running the one
99automatically generated test </span>
100
101Cargo compiled and ran our test. After the `Compiling`, `Finished`, and
102`Running` lines, we see the line `running 1 test`. The next line shows the name
103of the generated test function, called `it_works`, and the result of running
104that test, `ok`. Then we see the overall summary of running the tests: `test
105result: ok.` means all the tests passed. `1 passed; 0 failed` adds up the
106number of tests that passed or failed.
107
108We don't have any tests we've marked as ignored, so the summary says `0
109ignored`. We're going to talk about ignoring tests in the next section on
110different ways to run tests. The `0 measured` statistic is for benchmark tests
111that measure performance. Benchmark tests are, as of this writing, only
112available in nightly Rust. See Appendix D for more information about nightly
113Rust.
114
115The next part of the test output that starts with `Doc-tests adder` is for the
116results of any documentation tests. We don't have any documentation tests yet,
117but Rust can compile any code examples that appear in our API documentation.
118This feature helps us keep our docs and our code in sync! We'll be talking
119about how to write documentation tests in the "Documentation Comments" section
120of Chapter 14. We're going to ignore the `Doc-tests` output for now.
121
122<!-- I might suggest changing the name of the function, could be misconstrued
123as part of the test output! -->
124<!-- `it_works` is always the name that `cargo new` generates for the first
125test function, though. We wanted to show the reader what happens when you run
126the tests immediately after generating a new project; they pass without you
127needing to change anything. I've added a bit to walk through changing the
128function name and seeing how the output changes; I hope that's sufficient.
129/Carol -->
130
131Let's change the name of our test and see how that changes the test output.
132Give the `it_works` function a different name, such as `exploration`, like so:
133
134<span class="filename">Filename: src/lib.rs</span>
135
136```rust
137#[cfg(test)]
138mod tests {
139 #[test]
140 fn exploration() {
141 }
142}
143```
144
145And run `cargo test` again. In the output, we'll now see `exploration` instead
146of `it_works`:
147
148```text
149running 1 test
150test tests::exploration ... ok
151
152test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
153```
154
155Let's add another test, but this time we'll make a test that fails! Tests fail
156when something in the test function panics. We talked about the simplest way to
157cause a panic in Chapter 9: call the `panic!` macro! Type in the new test so
158that your `src/lib.rs` now looks like Listing 11-3:
159
160<span class="filename">Filename: src/lib.rs</span>
161
162```rust
163#[cfg(test)]
164mod tests {
165 #[test]
166 fn exploration() {
167 }
168
169 #[test]
170 fn another() {
171 panic!("Make this test fail");
172 }
173}
174```
175
176<span class="caption">Listing 11-3: Adding a second test; one that will fail
177since we call the `panic!` macro </span>
178
179And run the tests again with `cargo test`. The output should look like Listing
18011-4, which shows that our `exploration` test passed and `another` failed:
181
182```text
183running 2 tests
184test tests::exploration ... ok
185test tests::another ... FAILED
186
187failures:
188
189---- tests::another stdout ----
190 thread 'tests::another' panicked at 'Make this test fail', src/lib.rs:9
191note: Run with `RUST_BACKTRACE=1` for a backtrace.
192
193failures:
194 tests::another
195
196test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured
197
198error: test failed
199```
200
201<span class="caption">Listing 11-4: Test results when one test passes and one
202test fails </span>
203
204Instead of `ok`, the line `test tests::another` says `FAILED`. We have two new
205sections between the individual results and the summary: the first section
206displays the detailed reason for the test failures. In this case, `another`
207failed because it `panicked at 'Make this test fail'`, which happened on
208*src/lib.rs* line 9. The next section lists just the names of all the failing
209tests, which is useful when there are lots of tests and lots of detailed
210failing test output. We can use the name of a failing test to run just that
211test in order to more easily debug it; we'll talk more about ways to run tests
212in the next section.
213
214Finally, we have the summary line: overall, our test result is `FAILED`. We had
2151 test pass and 1 test fail.
216
217Now that we've seen what the test results look like in different scenarios,
218let's look at some macros other than `panic!` that are useful in tests.
219
220### Checking Results with the `assert!` Macro
221
222The `assert!` macro, provided by the standard library, is useful when you want
223to ensure that some condition in a test evaluates to `true`. We give the
224`assert!` macro an argument that evaluates to a boolean. If the value is `true`,
225`assert!` does nothing and the test passes. If the value is `false`, `assert!`
226calls the `panic!` macro, which causes the test to fail. This is one macro that
227helps us check that our code is functioning in the way we intend.
228
229<!-- what kind of thing can be passed as an argument? Presumably when we use it
230for real we won't pass it `true` or `false` as an argument, but some condition
231that will evaluate to true or false? In which case, should below be phrased "If
232the argument evaluates to true" and an explanation of that? Or maybe even a
233working example would be better, this could be misleading -->
234<!-- We were trying to really break it down, to show just how the `assert!`
235macro works and what it looks like for it to pass or fail, before we got into
236calling actual code. We've changed this section to move a bit faster and just
237write actual tests instead. /Carol -->
238
239Remember all the way back in Chapter 5, Listing 5-9, where we had a `Rectangle`
240struct and a `can_hold` method, repeated here in Listing 11-5. Let's put this
241code in *src/lib.rs* instead of *src/main.rs* and write some tests for it using
242the `assert!` macro.
243
244<!-- Listing 5-9 wasn't marked as such; I'll fix it the next time I get Chapter
2455 for editing. /Carol -->
246
247<span class="filename">Filename: src/lib.rs</span>
248
249```rust
250#[derive(Debug)]
251pub struct Rectangle {
252 length: u32,
253 width: u32,
254}
255
256impl Rectangle {
257 pub fn can_hold(&self, other: &Rectangle) -> bool {
258 self.length > other.length && self.width > other.width
259 }
260}
261```
262
263<span class="caption">Listing 11-5: The `Rectangle` struct and its `can_hold`
264method from Chapter 5 </span>
265
266The `can_hold` method returns a boolean, which means it's a perfect use case
267for the `assert!` macro. In Listing 11-6, let's write a test that exercises the
268`can_hold` method by creating a `Rectangle` instance that has a length of 8 and
269a width of 7, and asserting that it can hold another `Rectangle` instance that
270has a length of 5 and a width of 1:
271
272<span class="filename">Filename: src/lib.rs</span>
273
274```rust
275#[cfg(test)]
276mod tests {
277 use super::*;
278
279 #[test]
280 fn larger_can_hold_smaller() {
281 let larger = Rectangle { length: 8, width: 7 };
282 let smaller = Rectangle { length: 5, width: 1 };
283
284 assert!(larger.can_hold(&smaller));
285 }
286}
287```
288
289<span class="caption">Listing 11-6: A test for `can_hold` that checks that a
290larger rectangle indeed holds a smaller rectangle </span>
291
292Note that we've added a new line inside the `tests` module: `use super::*;`.
293The `tests` module is a regular module that follows the usual visibility rules
294we covered in Chapter 7. Because we're in an inner module, we need to bring the
295code under test in the outer module into the scope of the inner module. We've
296chosen to use a glob here so that anything we define in the outer module is
297available to this `tests` module.
298
299We've named our test `larger_can_hold_smaller`, and we've created the two
300`Rectangle` instances that we need. Then we called the `assert!` macro and
301passed it the result of calling `larger.can_hold(&smaller)`. This expression is
302supposed to return `true`, so our test should pass. Let's find out!
303
304```text
305running 1 test
306test tests::larger_can_hold_smaller ... ok
307
308test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
309```
310
311It does pass! Let's add another test, this time asserting that a smaller
312rectangle cannot hold a larger rectangle:
313
314<span class="filename">Filename: src/lib.rs</span>
315
316```rust
317#[cfg(test)]
318mod tests {
319 use super::*;
320
321 #[test]
322 fn larger_can_hold_smaller() {
323 let larger = Rectangle { length: 8, width: 7 };
324 let smaller = Rectangle { length: 5, width: 1 };
325
326 assert!(larger.can_hold(&smaller));
327 }
328
329 #[test]
7cac9316 330 fn smaller_can_not_hold_larger() {
cc61c64b
XL
331 let larger = Rectangle { length: 8, width: 7 };
332 let smaller = Rectangle { length: 5, width: 1 };
333
334 assert!(!smaller.can_hold(&larger));
335 }
336}
337```
338
339Because the correct result of the `can_hold` function in this case is `false`,
340we need to negate that result before we pass it to the `assert!` macro. This
341way, our test will pass if `can_hold` returns `false`:
342
343```text
344running 2 tests
7cac9316 345test tests::smaller_can_not_hold_larger ... ok
cc61c64b
XL
346test tests::larger_can_hold_smaller ... ok
347
348test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured
349```
350
351Two passing tests! Now let's see what happens to our test results if we
352introduce a bug in our code. Let's change the implementation of the `can_hold`
353method to have a less-than sign when it compares the lengths where it's
354supposed to have a greater-than sign:
355
356```rust
357#[derive(Debug)]
358pub struct Rectangle {
359 length: u32,
360 width: u32,
361}
362
363impl Rectangle {
364 pub fn can_hold(&self, other: &Rectangle) -> bool {
365 self.length < other.length && self.width > other.width
366 }
367}
368```
369
370Running the tests now produces:
371
372```text
373running 2 tests
7cac9316 374test tests::smaller_can_not_hold_larger ... ok
cc61c64b
XL
375test tests::larger_can_hold_smaller ... FAILED
376
377failures:
378
379---- tests::larger_can_hold_smaller stdout ----
380 thread 'tests::larger_can_hold_smaller' panicked at 'assertion failed:
381 larger.can_hold(&smaller)', src/lib.rs:22
382note: Run with `RUST_BACKTRACE=1` for a backtrace.
383
384failures:
385 tests::larger_can_hold_smaller
386
387test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured
388```
389
390Our tests caught the bug! Since `larger.length` is 8 and `smaller.length` is 5,
391the comparison of the lengths in `can_hold` now returns `false` since 8 is not
392less than 5.
393
394### Testing Equality with the `assert_eq!` and `assert_ne!` Macros
395
396A common way to test functionality is to take the result of the code under test
397and the value we expect the code to return and check that they're equal. We
398could do this using the `assert!` macro and passing it an expression using the
399`==` operator. However, this is such a common test that the standard library
400provides a pair of macros to perform this test more conveniently: `assert_eq!`
401and `assert_ne!`. These macros compare two arguments for equality or
402inequality, respectively. They'll also print out the two values if the
403assertion fails, so that it's easier to see *why* the test failed, while the
404`assert!` macro only tells us that it got a `false` value for the `==`
405expression, not the values that lead to the `false` value.
406
407In Listing 11-7, let's write a function named `add_two` that adds two to its
408parameter and returns the result. Then let's test this function using the
409`assert_eq!` macro:
410
411<span class="filename">Filename: src/lib.rs</span>
412
413```rust
414pub fn add_two(a: i32) -> i32 {
415 a + 2
416}
417
418#[cfg(test)]
419mod tests {
420 use super::*;
421
422 #[test]
423 fn it_adds_two() {
424 assert_eq!(4, add_two(2));
425 }
426}
427```
428
429<span class="caption">Listing 11-7: Testing the function `add_two` using the
430`assert_eq!` macro </span>
431
432Let's check that it passes!
433
434```text
435running 1 test
436test tests::it_adds_two ... ok
437
438test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
439```
440
441The first argument we gave to the `assert_eq!` macro, 4, is equal to the result
442of calling `add_two(2)`. We see a line for this test that says `test
443tests::it_adds_two ... ok`, and the `ok` text indicates that our test passed!
444
445Let's introduce a bug into our code to see what it looks like when a test that
446uses `assert_eq!` fails. Change the implementation of the `add_two` function to
447instead add 3:
448
449```rust
450pub fn add_two(a: i32) -> i32 {
451 a + 3
452}
453```
454
455And run the tests again:
456
457```text
458running 1 test
459test tests::it_adds_two ... FAILED
460
461failures:
462
463---- tests::it_adds_two stdout ----
464 thread 'tests::it_adds_two' panicked at 'assertion failed: `(left ==
465 right)` (left: `4`, right: `5`)', src/lib.rs:11
466note: Run with `RUST_BACKTRACE=1` for a backtrace.
467
468failures:
469 tests::it_adds_two
470
471test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
472```
473
474Our test caught the bug! The `it_adds_two` test failed with the message ``
475assertion failed: `(left == right)` (left: `4`, right: `5`) ``. This message is
476useful and helps us get started debugging: it says the `left` argument to
477`assert_eq!` was 4, but the `right` argument, where we had `add_two(2)`, was 5.
478
479Note that in some languages and test frameworks, the parameters to the
480functions that assert two values are equal are called `expected` and `actual`
481and the order in which we specify the arguments matters. However, in Rust,
482they're called `left` and `right` instead, and the order in which we specify
483the value we expect and the value that the code under test produces doesn't
484matter. We could have written the assertion in this test as
485`assert_eq!(add_two(2), 4)`, which would result in a failure message that says
486`` assertion failed: `(left == right)` (left: `5`, right: `4`) ``.
487
488The `assert_ne!` macro will pass if the two values we give to it are not equal
489and fail if they are equal. This macro is most useful for cases when we're not
490sure exactly what a value *will* be, but we know what the value definitely
491*won't* be, if our code is functioning as we intend. For example, if we have a
492function that is guaranteed to change its input in some way, but the way in
493which the input is changed depends on the day of the week that we run our
494tests, the best thing to assert might be that the output of the function is not
495equal to the input.
496
497Under the surface, the `assert_eq!` and `assert_ne!` macros use the operators
498`==` and `!=`, respectively. When the assertions fail, these macros print their
499arguments using debug formatting, which means the values being compared must
500implement the `PartialEq` and `Debug` traits. All of the primitive types and
501most of the standard library types implement these traits. For structs and
502enums that you define, you'll need to implement `PartialEq` in order to be able
503to assert that values of those types are equal or not equal. You'll need to
504implement `Debug` in order to be able to print out the values in the case that
505the assertion fails. Because both of these traits are derivable traits, as we
506mentioned in Chapter 5, this is usually as straightforward as adding the
507`#[derive(PartialEq, Debug)]` annotation to your struct or enum definition. See
508Appendix C for more details about these and other derivable traits.
509
510### Custom Failure Messages
511
512We can also add a custom message to be printed with the failure message as
513optional arguments to `assert!`, `assert_eq!`, and `assert_ne!`. Any arguments
514specified after the one required argument to `assert!` or the two required
515arguments to `assert_eq!` and `assert_ne!` are passed along to the `format!`
516macro that we talked about in Chapter 8, so you can pass a format string that
517contains `{}` placeholders and values to go in the placeholders. Custom
518messages are useful in order to document what an assertion means, so that when
519the test fails, we have a better idea of what the problem is with the code.
520
521For example, let's say we have a function that greets people by name, and we
522want to test that the name we pass into the function appears in the output:
523
524<span class="filename">Filename: src/lib.rs</span>
525
526```rust
527pub fn greeting(name: &str) -> String {
528 format!("Hello {}!", name)
529}
530
531#[cfg(test)]
532mod tests {
533 use super::*;
534
535 #[test]
536 fn greeting_contains_name() {
537 let result = greeting("Carol");
538 assert!(result.contains("Carol"));
539 }
540}
541```
542
543The requirements for this program haven't been agreed upon yet, and we're
544pretty sure the `Hello` text at the beginning of the greeting will change. We
545decided we don't want to have to update the test for the name when that
546happens, so instead of checking for exact equality to the value returned from
547the `greeting` function, we're just going to assert that the output contains
548the text of the input parameter.
549
550Let's introduce a bug into this code to see what this test failure looks like,
551by changing `greeting` to not include `name`:
552
553```rust
554pub fn greeting(name: &str) -> String {
555 String::from("Hello!")
556}
557```
558
559Running this test produces:
560
561```text
562running 1 test
563test tests::greeting_contains_name ... FAILED
564
565failures:
566
567---- tests::greeting_contains_name stdout ----
568 thread 'tests::greeting_contains_name' panicked at 'assertion failed:
569 result.contains("Carol")', src/lib.rs:12
570note: Run with `RUST_BACKTRACE=1` for a backtrace.
571
572failures:
573 tests::greeting_contains_name
574```
575
576This just tells us that the assertion failed and which line the assertion is
577on. A more useful failure message in this case would print the value we did get
578from the `greeting` function. Let's change the test function to have a custom
579failure message made from a format string with a placeholder filled in with the
580actual value we got from the `greeting` function:
581
582```rust,ignore
583#[test]
584fn greeting_contains_name() {
585 let result = greeting("Carol");
586 assert!(
587 result.contains("Carol"),
588 "Greeting did not contain name, value was `{}`", result
589 );
590}
591```
592
593Now if we run the test again, we'll get a much more informative error message:
594
595```text
596---- tests::greeting_contains_name stdout ----
7cac9316 597 thread 'tests::greeting_contains_name' panicked at 'Greeting did not contain
cc61c64b
XL
598 name, value was `Hello`', src/lib.rs:12
599note: Run with `RUST_BACKTRACE=1` for a backtrace.
600```
601
602We can see the value we actually got in the test output, which would help us
603debug what happened instead of what we were expecting to happen.
604
605### Checking for Panics with `should_panic`
606
607In addition to checking that our code returns the correct values we expect,
608it's also important to check that our code handles error conditions as we
609expect. For example, consider the `Guess` type that we created in Chapter 9 in
610Listing 9-8. Other code that uses `Guess` is depending on the guarantee that
611`Guess` instances will only contain values between 1 and 100. We can write a
612test that ensures that attempting to create a `Guess` instance with a value
613outside that range panics.
614
615We can do this by adding another attribute, `should_panic`, to our test
616function. This attribute makes a test pass if the code inside the function
7cac9316 617panics, and the test will fail if the code inside the function does not panic.
cc61c64b
XL
618
619Listing 11-8 shows how we'd write a test that checks the error conditions of
620`Guess::new` happen when we expect:
621
622<span class="filename">Filename: src/lib.rs</span>
623
624```rust
625struct Guess {
626 value: u32,
627}
628
629impl Guess {
630 pub fn new(value: u32) -> Guess {
631 if value < 1 || value > 100 {
632 panic!("Guess value must be between 1 and 100, got {}.", value);
633 }
634
635 Guess {
7cac9316 636 value
cc61c64b
XL
637 }
638 }
639}
640
641#[cfg(test)]
642mod tests {
643 use super::*;
644
645 #[test]
646 #[should_panic]
647 fn greater_than_100() {
648 Guess::new(200);
649 }
650}
651```
652
653<span class="caption">Listing 11-8: Testing that a condition will cause a
654`panic!` </span>
655
656The `#[should_panic]` attribute goes after the `#[test]` attribute and before
657the test function it applies to. Let's see what it looks like when this test
658passes:
659
660```text
661running 1 test
662test tests::greater_than_100 ... ok
663
664test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured
665```
666
667Looks good! Now let's introduce a bug in our code, by removing the condition
668that the `new` function will panic if the value is greater than 100:
669
670```rust
671# struct Guess {
672# value: u32,
673# }
674#
675impl Guess {
676 pub fn new(value: u32) -> Guess {
677 if value < 1 {
678 panic!("Guess value must be between 1 and 100, got {}.", value);
679 }
680
681 Guess {
7cac9316 682 value
cc61c64b
XL
683 }
684 }
685}
686```
687
688If we run the test from Listing 11-8, it will fail:
689
690```text
691running 1 test
692test tests::greater_than_100 ... FAILED
693
694failures:
695
696failures:
697 tests::greater_than_100
698
699test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
700```
701
702We don't get a very helpful message in this case, but once we look at the test
703function, we can see that it's annotated with `#[should_panic]`. The failure we
704got means that the code in the function, `Guess::new(200)`, did not cause a
705panic.
706
707`should_panic` tests can be imprecise, however, because they only tell us that
708the code has caused some panic. A `should_panic` test would pass even if the
709test panics for a different reason than the one we were expecting to happen. To
710make `should_panic` tests more precise, we can add an optional `expected`
711parameter to the `should_panic` attribute. The test harness will make sure that
712the failure message contains the provided text. For example, consider the
713modified code for `Guess` in Listing 11-9 where the `new` function panics with
714different messages depending on whether the value was too small or too large:
715
716<span class="filename">Filename: src/lib.rs</span>
717
718```rust
719struct Guess {
720 value: u32,
721}
722
723impl Guess {
724 pub fn new(value: u32) -> Guess {
725 if value < 1 {
726 panic!("Guess value must be greater than or equal to 1, got {}.",
727 value);
728 } else if value > 100 {
729 panic!("Guess value must be less than or equal to 100, got {}.",
730 value);
731 }
732
733 Guess {
7cac9316 734 value
cc61c64b
XL
735 }
736 }
737}
738
739#[cfg(test)]
740mod tests {
741 use super::*;
742
743 #[test]
744 #[should_panic(expected = "Guess value must be less than or equal to 100")]
745 fn greater_than_100() {
746 Guess::new(200);
747 }
748}
749```
750
751<span class="caption">Listing 11-9: Testing that a condition will cause a
752`panic!` with a particular panic message </span>
753
754This test will pass, because the value we put in the `expected` parameter of
755the `should_panic` attribute is a substring of the message that the
756`Guess::new` function panics with. We could have specified the whole panic
757message that we expect, which in this case would be `Guess value must be less
758than or equal to 100, got 200.` It depends on how much of the panic message is
759unique or dynamic and how precise you want your test to be. In this case, a
760substring of the panic message is enough to ensure that the code in the
761function that gets run is the `else if value > 100` case.
762
763To see what happens when a `should_panic` test with an `expected` message
764fails, let's again introduce a bug into our code by swapping the bodies of the
765`if value < 1` and the `else if value > 100` blocks:
766
767```rust,ignore
768if value < 1 {
769 panic!("Guess value must be less than or equal to 100, got {}.", value);
770} else if value > 100 {
771 panic!("Guess value must be greater than or equal to 1, got {}.", value);
772}
773```
774
775This time when we run the `should_panic` test, it will fail:
776
777```text
778running 1 test
779test tests::greater_than_100 ... FAILED
780
781failures:
782
783---- tests::greater_than_100 stdout ----
784 thread 'tests::greater_than_100' panicked at 'Guess value must be greater
785 than or equal to 1, got 200.', src/lib.rs:10
786note: Run with `RUST_BACKTRACE=1` for a backtrace.
787note: Panic did not include expected string 'Guess value must be less than or
788equal to 100'
789
790failures:
791 tests::greater_than_100
792
793test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured
794```
795
796The failure message indicates that this test did indeed panic as we expected,
797but the panic message `did not include expected string 'Guess value must be
798less than or equal to 100'`. We can see the panic message that we did get,
799which in this case was `Guess value must be greater than or equal to 1, got
800200.` We could then start figuring out where our bug was!
801
802Now that we've gone over ways to write tests, let's look at what is happening
803when we run our tests and talk about the different options we can use with
804`cargo test`.