From b1d0c5bb38913658f26254a5e9aff3550b8cf607 Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Sun, 23 Oct 2016 15:14:53 -0700 Subject: [PATCH 1/6] Update testing.md to reflect changes to cargo new `cargo new` now creates a `src/lib.rs` with a `tests` module by default. I've updated the earlier examples in this doc to reflect this. However, I don't know how we want to approach the "introduction" to idiomatic testing that follows in "the tests module" section. I _think_ it should be broken apart, with the module concept being introduced early on, and the `super` concept being addressed when we hit the `add_two` example. I'd like to get agreement on that being the right approach before I do it though. I _also_ removed the `#fn main() {}` hidden at the beginning of each example, as these cause Rust Playground to not treat the file as a set of tests that it can run. Removing it _should_ cause Rust Playground to display a "Test >" button in the top left when a user runs the code, which will allow them to see the test runner output. --- src/doc/book/testing.md | 126 ++++++++++++++++++++++++---------------- 1 file changed, 76 insertions(+), 50 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 0e6cdb8f09ddc..1ae093afafe8b 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -38,8 +38,9 @@ currently has no body. That's good enough to pass! We can run the tests with ```bash $ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///private/tmp/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.15 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test tests::it_works ... ok @@ -61,11 +62,11 @@ those later. For now, see this line: test tests::it_works ... ok ``` -Note the `it_works`. This comes from the name of our function: +Note the `tests::it_works`. This comes from the name of our module and function: ```rust fn it_works() { -# } +} ``` We also get a summary line: @@ -78,10 +79,12 @@ So why does our do-nothing test pass? Any test which doesn't `panic!` passes, and any test that does `panic!` fails. Let's make our test fail: ```rust -# fn main() {} -#[test] -fn it_works() { - assert!(false); +#[cfg(test)] +mod tests { + #[test] + fn it_works() { + assert!(false); + } } ``` @@ -91,16 +94,18 @@ run our tests again: ```bash $ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///private/tmp/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test tests::it_works ... FAILED failures: ----- test::it_works stdout ---- +---- tests::it_works stdout ---- thread 'tests::it_works' panicked at 'assertion failed: false', src/lib.rs:5 +note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: @@ -148,20 +153,24 @@ This is useful if you want to integrate `cargo test` into other tooling. We can invert our test's failure with another attribute: `should_panic`: ```rust -# fn main() {} -#[test] -#[should_panic] -fn it_works() { - assert!(false); +#[cfg(test)] +mod tests { + #[test] + #[should_panic] + fn it_works() { + assert!(false); + } } + ``` This test will now succeed if we `panic!` and fail if we complete. Let's try it: ```bash $ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///private/tmp/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test tests::it_works ... ok @@ -179,11 +188,13 @@ Rust provides another macro, `assert_eq!`, that compares two arguments for equality: ```rust -# fn main() {} -#[test] -#[should_panic] -fn it_works() { - assert_eq!("Hello", "world"); +#[cfg(test)] +mod tests { + #[test] + #[should_panic] + fn it_works() { + assert_eq!("Hello", "world"); + } } ``` @@ -192,8 +203,9 @@ passes: ```bash $ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///private/tmp/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.21 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test test tests::it_works ... ok @@ -214,25 +226,31 @@ make sure that the failure message contains the provided text. A safer version of the example above would be: ```rust -# fn main() {} -#[test] -#[should_panic(expected = "assertion failed")] -fn it_works() { - assert_eq!("Hello", "world"); +#[cfg(test)] +mod tests { + #[test] + #[should_panic(expected = "assertion failed")] + fn it_works() { + assert_eq!("Hello", "world"); + } } ``` That's all there is to the basics! Let's write one 'real' test: ```rust,ignore -# fn main() {} pub fn add_two(a: i32) -> i32 { a + 2 } -#[test] -fn it_works() { - assert_eq!(4, add_two(2)); +#[cfg(test)] +mod tests { + use super::add_two; + + #[test] + fn it_works() { + assert_eq!(4, add_two(2)); + } } ``` @@ -245,16 +263,24 @@ Sometimes a few specific tests can be very time-consuming to execute. These can be disabled by default by using the `ignore` attribute: ```rust -# fn main() {} -#[test] -fn it_works() { - assert_eq!(4, add_two(2)); +pub fn add_two(a: i32) -> i32 { + a + 2 } -#[test] -#[ignore] -fn expensive_test() { - // code that takes an hour to run +#[cfg(test)] +mod tests { + use super::add_two; + + #[test] + fn it_works() { + assert_eq!(4, add_two(2)); + } + + #[test] + #[ignore] + fn expensive_test() { + // code that takes an hour to run + } } ``` @@ -263,12 +289,13 @@ not: ```bash $ cargo test - Compiling adder v0.1.0 (file:///home/you/projects/adder) - Running target/debug/deps/adder-91b3e234d4ed382a + Compiling adder v0.1.0 (file:///private/tmp/adder) + Finished debug [unoptimized + debuginfo] target(s) in 0.20 secs + Running target/debug/deps/adder-941f01916ca4a642 running 2 tests -test expensive_test ... ignored -test it_works ... ok +test tests::expensive_test ... ignored +test tests::it_works ... ok test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured @@ -283,10 +310,11 @@ The expensive tests can be run explicitly using `cargo test -- --ignored`: ```bash $ cargo test -- --ignored - Running target/debug/deps/adder-91b3e234d4ed382a + Finished debug [unoptimized + debuginfo] target(s) in 0.0 secs + Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test expensive_test ... ok +test tests::expensive_test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -310,7 +338,6 @@ was missing from our last example. Let's explain what this does. The idiomatic way of writing our example looks like this: ```rust,ignore -# fn main() {} pub fn add_two(a: i32) -> i32 { a + 2 } @@ -339,7 +366,6 @@ a large module, and so this is a common use of globs. Let's change our `src/lib.rs` to make use of it: ```rust,ignore -# fn main() {} pub fn add_two(a: i32) -> i32 { a + 2 } From d9c60ca06c2400eba893d1efd2407d046a395862 Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2016 07:30:20 -0800 Subject: [PATCH 2/6] Instruct play.rust-lang.org to treat code as tests Without these changes, play.rust-lang.org (as of today) would wrap our examples in `fn main() {}`. This prevents the user from being able to easily run the tests. --- src/doc/book/testing.md | 48 +++++++++++++++++++++++++++++++++++++++-- 1 file changed, 46 insertions(+), 2 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 1ae093afafe8b..c36e0c09401bc 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -24,6 +24,10 @@ Cargo will automatically generate a simple test when you make a new project. Here's the contents of `src/lib.rs`: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[cfg(test)] mod tests { #[test] @@ -79,6 +83,10 @@ So why does our do-nothing test pass? Any test which doesn't `panic!` passes, and any test that does `panic!` fails. Let's make our test fail: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[cfg(test)] mod tests { #[test] @@ -153,6 +161,10 @@ This is useful if you want to integrate `cargo test` into other tooling. We can invert our test's failure with another attribute: `should_panic`: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[cfg(test)] mod tests { #[test] @@ -188,6 +200,10 @@ Rust provides another macro, `assert_eq!`, that compares two arguments for equality: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[cfg(test)] mod tests { #[test] @@ -226,6 +242,10 @@ make sure that the failure message contains the provided text. A safer version of the example above would be: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# #[cfg(test)] mod tests { #[test] @@ -239,6 +259,10 @@ mod tests { That's all there is to the basics! Let's write one 'real' test: ```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -263,6 +287,10 @@ Sometimes a few specific tests can be very time-consuming to execute. These can be disabled by default by using the `ignore` attribute: ```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -338,6 +366,10 @@ was missing from our last example. Let's explain what this does. The idiomatic way of writing our example looks like this: ```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -366,6 +398,10 @@ a large module, and so this is a common use of globs. Let's change our `src/lib.rs` to make use of it: ```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# pub fn add_two(a: i32) -> i32 { a + 2 } @@ -415,9 +451,14 @@ To write an integration test, let's make a `tests` directory and put a `tests/integration_test.rs` file inside with this as its contents: ```rust,ignore +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# +# // Sadly, this code will not work in play.rust-lang.org, because we have no +# // crate adder to import. You'll need to try this part on your own machine. extern crate adder; -# fn main() {} #[test] fn it_works() { assert_eq!(4, adder::add_two(2)); @@ -478,7 +519,10 @@ running examples in your documentation (**note:** this only works in library crates, not binary crates). Here's a fleshed-out `src/lib.rs` with examples: ```rust,ignore -# fn main() {} +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# //! The `adder` crate provides functions that add numbers to other numbers. //! //! # Examples From 35903bb9aae79fd29476fd9fb63971e75bb82b0a Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2016 07:48:01 -0800 Subject: [PATCH 3/6] Remove `mod tests` from earlier sections The narrative flows better if we follow what @steveklabnik is doing in rust-lang/book#288. Therefore, I completely copied it. --- src/doc/book/testing.md | 113 ++++++++++++++++++---------------------- 1 file changed, 51 insertions(+), 62 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index c36e0c09401bc..9cb3e5e48acea 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -36,6 +36,18 @@ mod tests { } ``` +For now, let's remove the `mod` bit, and focus on just the function: + +```rust +# // The next line exists to trick play.rust-lang.org into running our code as a +# // test: +# // fn main +# +#[test] +fn it_works() { +} +``` + Note the `#[test]`. This attribute indicates that this is a test function. It currently has no body. That's good enough to pass! We can run the tests with `cargo test`: @@ -47,7 +59,7 @@ $ cargo test Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... ok +test it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -63,10 +75,10 @@ for the test we wrote, and another for documentation tests. We'll talk about those later. For now, see this line: ```text -test tests::it_works ... ok +test it_works ... ok ``` -Note the `tests::it_works`. This comes from the name of our module and function: +Note the `it_works`. This comes from the name of our module and function: ```rust fn it_works() { @@ -87,12 +99,9 @@ and any test that does `panic!` fails. Let's make our test fail: # // test: # // fn main # -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert!(false); - } +#[test] +fn it_works() { + assert!(false); } ``` @@ -107,17 +116,17 @@ $ cargo test Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... FAILED +test it_works ... FAILED failures: ----- tests::it_works stdout ---- - thread 'tests::it_works' panicked at 'assertion failed: false', src/lib.rs:5 +---- it_works stdout ---- + thread 'it_works' panicked at 'assertion failed: false', src/lib.rs:5 note: Run with `RUST_BACKTRACE=1` for a backtrace. failures: - tests::it_works + it_works test result: FAILED. 0 passed; 1 failed; 0 ignored; 0 measured @@ -127,7 +136,7 @@ error: test failed Rust indicates that our test failed: ```text -test tests::it_works ... FAILED +test it_works ... FAILED ``` And that's reflected in the summary line: @@ -165,15 +174,11 @@ We can invert our test's failure with another attribute: `should_panic`: # // test: # // fn main # -#[cfg(test)] -mod tests { - #[test] - #[should_panic] - fn it_works() { - assert!(false); - } +#[test] +#[should_panic] +fn it_works() { + assert!(false); } - ``` This test will now succeed if we `panic!` and fail if we complete. Let's try it: @@ -185,7 +190,7 @@ $ cargo test Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... ok +test it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -204,13 +209,10 @@ equality: # // test: # // fn main # -#[cfg(test)] -mod tests { - #[test] - #[should_panic] - fn it_works() { - assert_eq!("Hello", "world"); - } +#[test] +#[should_panic] +fn it_works() { + assert_eq!("Hello", "world"); } ``` @@ -224,7 +226,7 @@ $ cargo test Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::it_works ... ok +test it_works ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured @@ -246,13 +248,10 @@ of the example above would be: # // test: # // fn main # -#[cfg(test)] -mod tests { - #[test] - #[should_panic(expected = "assertion failed")] - fn it_works() { - assert_eq!("Hello", "world"); - } +#[test] +#[should_panic(expected = "assertion failed")] +fn it_works() { + assert_eq!("Hello", "world"); } ``` @@ -267,14 +266,9 @@ pub fn add_two(a: i32) -> i32 { a + 2 } -#[cfg(test)] -mod tests { - use super::add_two; - - #[test] - fn it_works() { - assert_eq!(4, add_two(2)); - } +#[test] +fn it_works() { + assert_eq!(4, add_two(2)); } ``` @@ -295,20 +289,15 @@ pub fn add_two(a: i32) -> i32 { a + 2 } -#[cfg(test)] -mod tests { - use super::add_two; - - #[test] - fn it_works() { - assert_eq!(4, add_two(2)); - } +#[test] +fn it_works() { + assert_eq!(4, add_two(2)); +} - #[test] - #[ignore] - fn expensive_test() { - // code that takes an hour to run - } +#[test] +#[ignore] +fn expensive_test() { + // code that takes an hour to run } ``` @@ -322,8 +311,8 @@ $ cargo test Running target/debug/deps/adder-941f01916ca4a642 running 2 tests -test tests::expensive_test ... ignored -test tests::it_works ... ok +test expensive_test ... ignored +test it_works ... ok test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured @@ -342,7 +331,7 @@ $ cargo test -- --ignored Running target/debug/deps/adder-941f01916ca4a642 running 1 test -test tests::expensive_test ... ok +test expensive_test ... ok test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured From dd9280920f1f3ccf6a481ecd499434e6054c39d2 Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2016 07:52:51 -0800 Subject: [PATCH 4/6] Change project path for consistency I had used `/tmp/adder` for my previous commits. Flipped over to `/home/you/projects/adder` for consistency with other parts of testing.md --- src/doc/book/testing.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 9cb3e5e48acea..95194976c2926 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -54,7 +54,7 @@ currently has no body. That's good enough to pass! We can run the tests with ```bash $ cargo test - Compiling adder v0.1.0 (file:///private/tmp/adder) + Compiling adder v0.1.0 (file:///home/you/projects/adder) Finished debug [unoptimized + debuginfo] target(s) in 0.15 secs Running target/debug/deps/adder-941f01916ca4a642 @@ -111,7 +111,7 @@ run our tests again: ```bash $ cargo test - Compiling adder v0.1.0 (file:///private/tmp/adder) + Compiling adder v0.1.0 (file:///home/you/projects/adder) Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs Running target/debug/deps/adder-941f01916ca4a642 @@ -185,7 +185,7 @@ This test will now succeed if we `panic!` and fail if we complete. Let's try it: ```bash $ cargo test - Compiling adder v0.1.0 (file:///private/tmp/adder) + Compiling adder v0.1.0 (file:///home/you/projects/adder) Finished debug [unoptimized + debuginfo] target(s) in 0.17 secs Running target/debug/deps/adder-941f01916ca4a642 @@ -221,7 +221,7 @@ passes: ```bash $ cargo test - Compiling adder v0.1.0 (file:///private/tmp/adder) + Compiling adder v0.1.0 (file:///home/you/projects/adder) Finished debug [unoptimized + debuginfo] target(s) in 0.21 secs Running target/debug/deps/adder-941f01916ca4a642 @@ -306,7 +306,7 @@ not: ```bash $ cargo test - Compiling adder v0.1.0 (file:///private/tmp/adder) + Compiling adder v0.1.0 (file:///home/you/projects/adder) Finished debug [unoptimized + debuginfo] target(s) in 0.20 secs Running target/debug/deps/adder-941f01916ca4a642 From 4cf764470a84b68445db2529f17371a0f6ab2023 Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2016 07:55:20 -0800 Subject: [PATCH 5/6] Remove extraneous word --- src/doc/book/testing.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 95194976c2926..4fd73e4854bc4 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -78,7 +78,7 @@ those later. For now, see this line: test it_works ... ok ``` -Note the `it_works`. This comes from the name of our module and function: +Note the `it_works`. This comes from the name of our function: ```rust fn it_works() { From 2a832a03c5a3efd6388e4eb5c5b5b4568bcd80f6 Mon Sep 17 00:00:00 2001 From: Trotter Cashion Date: Thu, 10 Nov 2016 19:08:45 -0800 Subject: [PATCH 6/6] Ignore tests failing due to lack of `fn main` While the commit message on this one sounds terrible, it's really not so bad. The issue is that our test runner _expects_ a `fn main() {}` in code blocks that it'll test, but this code really shouldn't have them. If it did, then clicking the "play" link in the docs would result in play.rust-lang.org not treating this code as a test example to be run. --- src/doc/book/testing.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/doc/book/testing.md b/src/doc/book/testing.md index 4fd73e4854bc4..ed916fd798bb6 100644 --- a/src/doc/book/testing.md +++ b/src/doc/book/testing.md @@ -23,7 +23,7 @@ $ cd adder Cargo will automatically generate a simple test when you make a new project. Here's the contents of `src/lib.rs`: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -38,7 +38,7 @@ mod tests { For now, let's remove the `mod` bit, and focus on just the function: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -81,8 +81,10 @@ test it_works ... ok Note the `it_works`. This comes from the name of our function: ```rust +# fn main() { fn it_works() { } +# } ``` We also get a summary line: @@ -94,7 +96,7 @@ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured So why does our do-nothing test pass? Any test which doesn't `panic!` passes, and any test that does `panic!` fails. Let's make our test fail: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -169,7 +171,7 @@ This is useful if you want to integrate `cargo test` into other tooling. We can invert our test's failure with another attribute: `should_panic`: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -204,7 +206,7 @@ test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured Rust provides another macro, `assert_eq!`, that compares two arguments for equality: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -243,7 +245,7 @@ parameter can be added to the `should_panic` attribute. The test harness will make sure that the failure message contains the provided text. A safer version of the example above would be: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main @@ -280,7 +282,7 @@ some known arguments and compare it to the expected output. Sometimes a few specific tests can be very time-consuming to execute. These can be disabled by default by using the `ignore` attribute: -```rust +```rust,ignore # // The next line exists to trick play.rust-lang.org into running our code as a # // test: # // fn main