# 2019-09-11 rust meetup malaysia # used with git.suckless.org/sent Testing! Back to basics. \ o unit o integration o end-to-end 1. Unit testing Hello world pub fn add(x: i32, y: i32) -> i32 { x + y } \#[test] fn test_add() { assert_eq!(add(1, 1), 2); } pub fn add(x: i32, y: i32) -> i32 { x + y } \ \#[test] fn test_add() { assert_eq!(add(1, 1), 2); } > cargo test Compiling tests v0.1.0 (/tmp/tests) Finished dev [unoptimized + debuginfo] target(s) in 0.32s Running target/debug/deps/tests-c8151b00b820f92b \ running 1 test test test_add ... ok \ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Building blocks (macros) \ o assert!() o assert_eq!() o assert_ne!() \#[test] fn test_add() { assert_eq!(add(1, 1), 2); assert_ne!(add(1, 1), 3); } \#[test] fn test_rust_my() { assert!("rust malaysia".contains("rust")); } > cargo test Compiling tests v0.1.0 (/tmp/tests) Finished dev [unoptimized + debuginfo] target(s) in 0.39s Running target/debug/deps/tests-c8151b00b820f92b \ running 2 tests test test_add ... ok test test_rust_my ... ok \ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Just in case you wonder. :P > cargo test Compiling tests v0.1.0 (/tmp/tests) Finished dev [unoptimized + debuginfo] target(s) in 0.39s Running target/debug/deps/tests-c8151b00b820f92b \ running 3 tests test test_add ... ok test test_rust_my ... ok test test_huh ... FAILED \ failures: \ ---- test_huh stdout ---- thread 'test_huh' panicked at 'assertion failed: `(left == right)` left: `2`, right: `3`', src/main.rs:13:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. \ \ failures: test_huh \ test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out \ error: test failed, to rerun pass '--bin tests' Test also keeps your outputs. ^^ pub fn add(x: i32, y: i32) -> i32 { dbg!(x, y); x + y } > cargo test Compiling tests v0.1.0 (/tmp/tests) Finished dev [unoptimized + debuginfo] target(s) in 0.41s Running target/debug/deps/tests-c8151b00b820f92b \ running 3 tests test test_add ... ok test test_rust_my ... ok test test_huh ... FAILED \ failures: \ ---- test_huh stdout ---- [src/main.rs:2] x = 1 [src/main.rs:2] y = 1 thread 'test_huh' panicked at 'assertion failed: `(left == right)` left: `2`, right: `3`', src/main.rs:14:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. \ \ failures: test_huh \ test result: FAILED. 2 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out \ error: test failed, to rerun pass '--bin tests' @test.png And also cached, rust is getting faster. Next example We should just ignore these tests. #[test] +#[ignore] fn test_add() { assert_eq!(add(1, 1), 2); assert_ne!(add(1, 1), 3); } > cargo test Compiling tests v0.1.0 (/tmp/tests) Finished dev [unoptimized + debuginfo] target(s) in 0.37s Running target/debug/deps/tests-c8151b00b820f92b \ running 3 tests test test_add ... ignored test test_huh ... ignored test test_rust_my ... ignored \ test result: ok. 0 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out ... Plane CRASHED What? Run What if rust panics? pub fn div(x: i32, y: i32) -> i32 { x / y } \#[test] fn test_div() { assert_eq!(div(2, 1), 2); assert_eq!(div(1, 1), 1); } > cargo test Compiling tests v0.1.0 (/tmp/tests) Finished dev [unoptimized + debuginfo] target(s) in 0.38s Running target/debug/deps/tests-c8151b00b820f92b \ running 4 tests test test_add ... ignored test test_huh ... ignored test test_rust_my ... ignored test test_div ... ok \ test result: ok. 1 passed; 0 failed; 3 ignored; 0 measured; 0 filtered out \#[test] fn test_sad() { assert_eq!(div(1, 0), 0); } _ ._ _ , _ ._ (_ ' ( ` )_ .__) ( ( ( ) `) ) _) (__ (_ (_ . _) _) ,__) `~~`\ ' . /`~~` ; ; / \ _____________/_ __ \_____________ > cargo test Finished dev [unoptimized + debuginfo] target(s) in 0.01s Running target/debug/deps/tests-c8151b00b820f92b \ running 5 tests test test_add ... ignored test test_huh ... ignored test test_rust_my ... ignored test test_div ... ok test test_sad ... FAILED \ failures: \ ---- test_sad stdout ---- thread 'test_sad' panicked at 'attempt to divide by zero', src/main.rs:26:5 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. \ \ failures: test_sad \ test result: FAILED. 1 passed; 1 failed; 3 ignored; 0 measured; 0 filtered out \ error: test failed, to rerun pass '--bin tests' How? \#[test] \#[should_panic] fn test_sad() { assert_eq!(div(1, 0), 0); } Even better \#[test] \#[should_panic(expected = "attempt to divide by zero")] fn test_sad() { assert_eq!(div(1, 0), 0); } Let's ignore the tests for now. Coming from Python. 2. Documentation testing /// Multiply x with y. /// /// # Examples /// /// ``` /// assert_eq!(mul(2, 3), 6); /// ``` pub fn mul(x: i32, y: i32) -> i32 { x * y } Familiar? @doc_home.png @doc_mul.png > cargo test Compiling tests v0.1.0 (/tmp/tests) Finished dev [unoptimized + debuginfo] target(s) in 0.42s Running target/debug/deps/tests-eaef7bb9c33b7c68 \ running 5 tests test test_add ... ignored test test_div ... ignored test test_huh ... ignored test test_rust_my ... ignored test test_sad ... ok \ test result: ok. 1 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out \ Doc-tests tests \ running 1 test test src/lib.rs - mul (line 46) ... ok \ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Hiding lines - @doc_div.png > cargo test Compiling tests v0.1.0 (/tmp/tests) Finished dev [unoptimized + debuginfo] target(s) in 0.39s Running target/debug/deps/tests-eaef7bb9c33b7c68 \ running 5 tests test test_add ... ignored test test_div ... ignored test test_huh ... ignored test test_rust_my ... ignored test test_sad ... ok \ test result: ok. 1 passed; 0 failed; 4 ignored; 0 measured; 0 filtered out \ Doc-tests tests \ running 2 tests test src/lib.rs - mul (line 55) ... ok test src/lib.rs - div (line 29) ... ok \ test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out Guess what is `x` and `y`? /// Divide x by y. /// /// # Examples /// /// ``` /// # let x = -1; /// # let y = -1; /// assert_eq!(tests::div(x, y), 1); /// ``` pub fn div(x: i32, y: i32) -> i32 { x / y } 3. Benchmark tests (nightly) #![feature(test)] extern crate test; \ \#[bench] fn bench_add_fn(b: &mut Bencher) { b.iter(|| add(1, 2)); } > cargo +nightly test bench Finished dev [unoptimized + debuginfo] target(s) in 0.01s Running target/debug/deps/tests-0682c0d136de777b \ running 1 test test bench_add_fn ... ok \ test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 5 filtered out > cargo +nightly bench bench Finished release [optimized] target(s) in 0.01s Running target/release/deps/tests-9f6bca5df77d8150 \ running 1 test test bench_add_fn ... bench: 827 ns/iter (+/- 40) \ test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured; 5 filtered out Just for fun. \#[bench] fn bench_add_native(b: &mut Bencher) { b.iter(|| 1 + 2); } > cargo +nightly bench bench Compiling tests v0.1.0 (/tmp/tests) Finished release [optimized] target(s) in 0.57s Running target/release/deps/tests-9f6bca5df77d8150 \ running 2 tests test bench_add_fn ... bench: 805 ns/iter (+/- 50) test bench_add_native ... bench: 0 ns/iter (+/- 0) \ test result: ok. 0 passed; 0 failed; 0 ignored; 2 measured; 5 filtered out 0ns? Next: - test::black_box - bencher.bytes :q