#test #testing #cargo #binary #integration


Build a program under a crate for integration tests

3 stable releases

Uses new Rust 2021

2.0.0 Aug 5, 2022
1.0.1 May 12, 2022

#123 in Testing

23 downloads per month
Used in calloop-subproc

MIT license

164 lines

Maintenance License Coverage Rust


Test binary generation for integration tests under Cargo.


This crate primarily exists to work around Cargo issue #1982. If that has been fixed, you probably don't need this.

If you have integration tests for things that involve subprocess management, inter-process communication, or platform tools, you might need to write some mock binaries of your own to test against. And if you're already using Cargo to build and test, it would be nice to be able to write those test binaries in Rust, near to the crate you're testing, as cargo projects themselves.

This crate provides a simple interface for invoking Cargo to build test binaries organised in a separate directory under your crate.

The first thing to note is that these test binaries aren't binaries listed in your actual project's manifest. If that's what you have and it works, you don't need this crate at all — you can just use CARGO_BIN_EXE_<name>.

But maybe the test binaries have to be made into separate projects because they have extra dependencies. Pick a directory name and put them in there eg. this project uses testbins. This is not going to be a workspace. Under this directory you will have each test binary as a separate Cargo project, just like any other Rust binary.

The structure should look something like this:

├── Cargo.toml        (this crate's manifest)
├── src
│  └── lib.rs         (this crate's lib.rs)
├── testbins          (all the test binary projects are under this
│  │                   directory)
│  ├── test-something (one test binary)
│  │  ├── Cargo.toml  (test binary manifest, name = "test-something")
│  │  └── src
│  │     └── main.rs  (test binary source)
│  ├── test-whatever  (another test binary)
│  │  ├── Cargo.toml
│  │  └── src
│  │     └── main.rs
│   ...etc...
└── tests
   └── tests.rs       (tests for this crate, which want to use the test
                       binaries above)


It can be useful to put an empty [workspace] section in the Cargo.toml for these test binaries, so that Cargo knows not to look in parent directories.

With this setup, you can now call build_test_binary("test-something", "testdir") where:

  • "test-something" is the binary name you'd pass to Cargo in the child project eg. cargo build --bin test-something; it also has to be the name of the subdirectory this project is in
  • "testdir" is the directory relative to your real project's manifest containing this test binary project (and maybe others)

If you need to change profiles or features, or have more control over the directory structure, there is also a builder API. Also see build_test_binary_once!() for a macro that lazily builds the binary and caches the path.

Here's an example of how you might use this in a test, with a binary named does-build:

let test_bin_path = build_test_binary("does-build", "testbins")
    .expect("error building test binary");
let mut test_bin_subproc = std::process::Command::new(test_bin_path)
    .expect("Error running test binary");

// Test behaviour of your program against the mock binary eg. send it
// something on stdin and assert what it prints on stdout, do some IPC,
// check for side effects.

    .expect("error waiting for test binary")

The result returned by these functions contains the path of the built binary as a [std::ffi::OsString], which can be passed to [std::process::Command] or other crates that deal with subprocesses. The path is not resolved to an absolute path, although it might be one anyway. Since it is the path provided by Cargo after being invoked in the current process' working directory, it will be valid as long as you do not change the working directory between obtaining it and using it.

Minimum supported Rust version: 1.57. Licensed under the MIT license (see LICENSE file in this directory).

This document is kept up-to-date with cargo-rdme.


~35K SLoC