# Controlling Tests

`cargo test` compiles your code in test mode then runs the resultant test binary in parallel and capturing the generated outputs, just like how `cargo run` compiles then runs the resultant code.


You can specify command line options to change this default behavior.

Some command line options that go into `cargo test` and some go to the resultant test binary

To separate these two arguments you list the arguments that go into `cargo test` followed by the separator `--` and then the ones that go to the test binary.

For example running `cargo test --help` displays the options you can use with `cargo test` and running `cargo test -- --help` displays the options you can use after the separator.

## Running Tests in Parallel or Consecutively
By default you run multiple tests that run in parallel using threads, which means they finish running faster and get feedback quicker.

You must ensure that your tests don't depend on each other or on any shared state, this includes a shared environment, with details such as working directory or environment variables.

One case where this would be a problem would be using a text file where the value is expected to something but another test changes that value which makes all other tests after invalid because the text file no longer contains the expected value

One solution to this to to make sure each test writes to a different life, the other solution is to run the tests one at a time.

If you dont want to run the tests in parallel or if you want more control over the number of threads used you can use the `--test-threads` flag and the number of threads you want to use to the test binary

Here is an example use
```bash
$ cargo test -- --test-threads=1
```

Here we have test the number of test threads to `1` which tells the program to not use any parallelism.

This is slower than running them in parallel, but the test won't interfere with each other if they share state.

## Showing Function Output
By default if a tests passes the Rust test library captures anything printed to the std output.

For example if we call `println!` in a test and the test passes we wont see the `println!` output in the terminal. But if the test fails we will see whatever was printed to the std output with the rest of the failure message.

For example in this the function prints the value of its parameter and returns 10 as well as a test that passes and a test that fails.

```rust
fn prints_and_returns_10(a: i32) -> i32 {
	println!("I got the value {a}");
	10
}

#[cfg(test)]
mod tests {
	use super::*;

	#[test]
	fn this_test_will_pass() {
		let value = prints_and_returns_10(4);
		assert_eq!(value, 10);
	}

	#[test]
	fn this_test_will_fail() {
		let value = prints_and_returns_10(8);
		assert_eq!(value, 5);
	}
}
```

Here is the output after running `cargo test`
```
$ cargo test
   Compiling silly-function v0.1.0 (file:///projects/silly-function)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.58s
     Running unittests src/lib.rs (target/debug/deps/silly_function-160869f38cff9166)

running 2 tests
test tests::this_test_will_fail ... FAILED
test tests::this_test_will_pass ... ok

failures:

---- tests::this_test_will_fail stdout ----
I got the value 8
thread 'tests::this_test_will_fail' panicked at src/lib.rs:19:9:
assertion `left == right` failed
  left: 10
 right: 5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::this_test_will_fail

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`
```

Note that we don't see `I got the value 4` in the output which is printed by the test that passes, that output has been captured.

The output from the test failed, `I got the value 8`, this appears in the section of the test summary output which also shows thew case of the test failure.

If we want to see printed values for the passing tests as well we can add the flag `--show-output`

Here is an example use
```bash
$ cargo test -- --show-output
```
If we run the test again with the `--show-output` flag, here is the output
```
$ cargo test -- --show-output
   Compiling silly-function v0.1.0 (file:///projects/silly-function)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.60s
     Running unittests src/lib.rs (target/debug/deps/silly_function-160869f38cff9166)

running 2 tests
test tests::this_test_will_fail ... FAILED
test tests::this_test_will_pass ... ok

successes:

---- tests::this_test_will_pass stdout ----
I got the value 4


successes:
    tests::this_test_will_pass

failures:

---- tests::this_test_will_fail stdout ----
I got the value 8
thread 'tests::this_test_will_fail' panicked at src/lib.rs:19:9:
assertion `left == right` failed
  left: 10
 right: 5
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace


failures:
    tests::this_test_will_fail

test result: FAILED. 1 passed; 1 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

error: test failed, to rerun pass `--lib`
```
## Running a Subset of Tests by Name
Sometimes, running a full test suite can take a long time

If are working in a particular area, you might want to run tests pertaining to the code area.

This can be done by passing `cargo test` then the name or names of the test(s) you want to run as an argument

Here we will write 3 tests on our `add_two` function
```rust
pub fn add_two(a: usize) -> usize {
    a + 2
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn add_two_and_two() {
        let result = add_two(2);
        assert_eq!(result, 4);
    }

    #[test]
    fn add_three_and_two() {
        let result = add_two(3);
        assert_eq!(result, 5);
    }

    #[test]
    fn one_hundred() {
        let result = add_two(100);
        assert_eq!(result, 102);
    }
}
```
If we run it with out any arguments here is the output
```
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.62s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 3 tests
test tests::add_three_and_two ... ok
test tests::add_two_and_two ... ok
test tests::one_hundred ... ok

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```

### Running Single Tests
We can pass the name of any test function to `cargo test` to only run that test

Here is the the output
```
$ cargo test one_hundred
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.69s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test tests::one_hundred ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 2 filtered out; finished in 0.00s
```

Note that `one_hundred` ran and outputted.

The other 2 tests didn't run as the other two didn't match that name.

The test lets us know how many tests we didn't run by displaying `2 filtered out` at the end

We can't specify the names of multiple tests this way, only the first value given to `cargo test` will be used
### Filtering to Run Multiple Tests
We can specify part of a tests name, and any test whose name matches that value will run

Here is an the output where we use `add` tow run the two tests who's name contains `add` in them
```
$ cargo test add
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.61s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 2 tests
test tests::add_three_and_two ... ok
test tests::add_two_and_two ... ok

test result: ok. 2 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s
```
Notice that this tests ran all tests wit `add` in the name and filtered out the test named `one_hundred`

Also note that the module in which a test appears becomes part of the test's name, so we can run all the tests in a module by filtering on the module's name.

### Ignoring Some Tests Unless Specifically Requested
Sometimes a few specific tests can be very time-consuming to execute, so you may choose to exclude those during most runs of `cargo test`

Rather than listing as arguments all tests you do want to run, instead you can annotate the time consuming tests using the `ignore` attribute to exclude them

Here is an example of this
```rust
#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn it_works() {
        let result = add(2, 2);
        assert_eq!(result, 4);
    }

    #[test]
    #[ignore]
    fn expensive_test() {
        // code that takes an hour to run
    }
}
```
After `#[test]` we add the `#[ignore]` line to the test we want to exclude

Now when we run our tests `it_works` runs but `expensive_test` doesn't

Here is the output
```
$ cargo test
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.60s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 2 tests
test tests::expensive_test ... ignored
test tests::it_works ... ok

test result: ok. 1 passed; 0 failed; 1 ignored; 0 measured; 0 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```

The `expensive_test` function is listed as `ignored`

If we want to run only the ignored tests we can use `cargo test -- --ignored`

Here is the output after running that command
```
$ cargo test -- --ignored
   Compiling adder v0.1.0 (file:///projects/adder)
    Finished `test` profile [unoptimized + debuginfo] target(s) in 0.61s
     Running unittests src/lib.rs (target/debug/deps/adder-92948b65e88960b4)

running 1 test
test expensive_test ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 1 filtered out; finished in 0.00s

   Doc-tests adder

running 0 tests

test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s
```

By controlling which tests we can get feedback quickly

When you get to a point where it makes sense to check the results of the `ignored` tests and you have to wait for the results, you can run `cargo test -- --ignored` instead

If you want to run all tests regardless of if they are ignored or not you can run `cargo test -- --include-ignored`