rustintegration-testing

Why is `CARGO_BIN_EXE_<name>` not present in tests?


When running the below test snippet against the binary with cargo test the environmental variable CARGO_BIN_EXE_<name> is not available.

Example Code

use std::env;

#[cfg(test)]
fn test_pub_sub() {
    let exe_filepath: String = env::var("CARGO_BIN_EXE_pub-sub-learning").unwrap();

    // Start a new process
    let mut sub_command = Command::new(exe_filepath)
        .arg("sub")
        .stdin(Stdio::piped())
        .stdout(Stdio::piped())
        .spawn()
        .expect("Failed to start pub");

    // ...
}

Error message

called `Result::unwrap()` on an `Err` value: NotPresent

Solution

  • I was doing a few things wrong.

    1. The tests were unit tests not integration tests. I had make the test an integration test by moving it to the tests directory next to src. Additionally, validate that the target is a binary (not a library).

    Files located under the tests directory are integration tests. When you run cargo test, Cargo will compile each of these files as a separate crate, and execute them.

    This is the Cargo.toml file that worked. Importantly, the package is setup to run with the entry point in file src/main.rs.

    [package]
    name = "pub-sub-learning"
    version = "0.1.0"
    edition = "2021"
    
    [dependencies]
    # skipping...
    
    1. Use env!("CARGO_BIN_EXE_<name>") instead of env::var("CARGO_BIN_EXE_<name>").

    This section of the Cargo Targets documentation hinted at the problem (emphasis added).

    Binary targets are automatically built if there is an integration test. This allows an integration test to execute the binary to exercise and test its behavior. The CARGO_BIN_EXE_<name> environment variable is set when the integration test is built so that it can use the env macro to locate the executable.

    An important note is that printing out the env::vars() is misleading. The env macro has access to env variables that are not in env::vars()!

    1. Another gotcha is to run cargo test from the CLI instead of an IDE.