This question is aimed at finding out people's approaches / recommendations for good practice, than a call for help.
I have a binary that loads configuration / assets, which should be next to the binary when installed. In development, the built binary lives in target/<profile>/<binary>[.exe]
.
Problem 1:
I want to be able to run cargo test [--release]
to test different sets of configuration.
Approach I've taken:
- In unit tests, I make an intermediate function which lets me pass in
PathBuf
so I can inject a path to a fake exe parent directory, to point it to a tempdir. The delta between the test code and the real code is "how to calculate the parent directory".
Problem 2:
I want to run cargo run [--release]
without additional "fluff". Additional "fluff" being copying configuration to the target/<profile>
directory. I don't want to do that because:
- It's incovenient / easy to forget a step / have stale config.
- It's not isolated if I wanted to run things in parallel, e.g. have integration tests that execute
cargo run
.
Approach taken:
-
In
#[cfg(test)]
mode, or when using thedebug
profile, tell the application to also searchoption_env!("OUT_DIR")
andoption_env!("CARGO_MANIFEST_DIR")
for default config. -
When using the
release
profile, look up anAPP_DIR
environmental variable to substitute the application's parent directory.The environmental variable allows the code to not contain information about the build environment, as well as allows tests in the
tests/
directory to do something like:- Set
APP_DIR=path/to/some/directory
. - Run
cargo run [--release]
. - Do assertions on the actual binary that will be released.
Humans still have to go
export APP_DIR=`pwd`; cargo run --release
to use the crate dev config. - Set
This does introduce an additional APP_DIR
input to the application. I guess git
does allow you to do something similar through its --git-dir
parameter.
Problem 3:
When running unit tests in the release
profile, library dependencies are not cfg(test)
, even if they are in the same crate workspace, so they don't pass the cfg!(test)
check to use dev config.
That's hard to understand in words, so here is a diagram:
// A -> B means A depends on B
lib_a -> lib_b -> lib_macro
-
lib_macro
provides a macro to load configuration from the current crate directory if it's intest
mode ordebug
mode. -
lib_b
loads configuration typeB
-
lib_a
useslib_b
I want lib_a
to store configuration for lib_b
for tests. In cargo test
, it loads fine from lib_a
's crate directory because lib_b
is compiled using the debug
profile. However when using cargo test --release
, it doesn't load fine, because in release
mode, lib_macro
doesn't insert the CARGO_MANIFEST_DIR
value as a base directory (to prevent leaking development values).
So, the approach I took was:
- Make
lib_a
set theAPP_DIR
environmental variable during tests.
This didn't feel clean, I don't know why.