Beyond unit tests in our library crate, we can also integration test our actual final binary.
There’s a few different ways to get the path to the cargo binary that gets built when you test, but the easiest I’ve found by far is to use the asset_cmd crate.
❯ cargo add --dev assert_cmd
Updating crates.io index
Adding assert_cmd v2.0.12 to dev-dependencies.
Features:
- color
- color-auto
Updating crates.io index
Integration tests live in the tests directory and only have access to the public interface of your library. Each Rust source file in the tests directory is compiled as a separate crate.
I’ve named my file integration.rs, but that can be whatever your want.
touch tests/integration.rs
Inside of integration.rs we can set up two tests. Each of them is fairly straightforward and only tests functionality that is created for us by clap, but it gives us a good idea of what it looks like to run a binary.
/// make sure help runs. This indicates the binary works
#[test]
fn test_help() {
assert_cmd::Command::cargo_bin("garden")
.unwrap()
.arg("--help")
.assert()
.success()
.stderr("");
}
/// make sure we have a write command by running `garden write --help`
#[test]
fn test_write_help() {
assert_cmd::Command::cargo_bin("garden")
.unwrap()
.arg("write")
.arg("--help")
.assert()
.success()
.stderr("");
}
assert_cmd::Command::cargo_bin is a function that will locate the cargo binary for us and create a assert_cmd::Command from it.
assert_cmd::Command allows us to build up the execution of our binary using builder functions and then execute that command.
For example, the first test builds garden --help and the second builds garden write --help.
assert then runs the command we’ve built, and allows us to test the output.
The Assert struct returned from the assert function includes a series of functions for testing the output. .success makes sure the command ran successfully, and .stderr allows us to test the output of stderr.
There’s no output on stderr for our binary when outputting help text, so we can test against an empty string.
For programs that don’t require interactivity this is often enough to exercise the different ways in which the binary can be used, from user input to CLI output and more.