Cargo test fails most ungracefully

Hi,

This does not look like my human error at all:

$ cargo test
   Compiling procrustes v1.0.3 (/home/user/spaces/rust/rs_procr)
    Finished test [unoptimized + debuginfo] target(s) in 2.98s
     Running unittests (target/debug/deps/procrustes-86413befaf6c9b48)

running 7 tests
test test_main::test_human_fine ... ok
test test_main::test_has_ext_of ... ok
error: The following required arguments were not provided:
    <src>
    <dst-dir>

USAGE:
    procrustes-86413befaf6c9b48 [FLAGS] [OPTIONS] <src> <dst-dir>

For more information try --help
error: test failed, to rerun pass '--bin procrustes'

This is a CLI script, powered by clap. The tests include pure functions, nothing else. No attempt to test the command line itself. The error simply has no place here. I tried

$ cargo clean

It did not help.

This shouldn't ordinarily happen.

Do you have any configuration for the binary in your Cargo.toml? (I'm thinking of harness = false as a possible problem here.)

Are you parsing command line options in some global/lazy-init way that might be getting called from the test functions (rather than in main())?

Showing complete code to reproduce the problem would help identify it.

GitHub repository

No shenanigans on my part that I'm aware of :slight_smile:

Just run

$ cargo test

The shenanigan is right here; it's the second possibility I mentioned above:

lazy_static! {
    static ref ARGS: ArgMatches<'static> = retrieve_args();

If any code at all, test or not, reads ARGS, then your retrieve_args() will ask clap to parse the process's argument list. When running a test binary with cargo test, that won't be your expected arguments.

My personal recommendation would be to stop using a static here at all, call retrieve_args() from main(), and pass the options (in narrowly-defined structs, not the entire ArgMatches) to each function that needs them. That way, it will never be called accidentally from a test. This also makes it much more straightforward to test the behavior under specific options — there's no invisible dependency, only an explicit one.

But, if you don't want to do that, what you can do is use cfg(test) to change how it is defined when running tests.

static ref ARGS: ArgMatches<'static> = {
    if cfg!(test) {
        // Or you could pass a different parameter to retrieve_args().
        constant_args_for_test()
    } else {
        retrieve_args()
    }
};
4 Likes

Thanks! I will work on it. The funny thing is, that lazy_static! thing is there from the beginning. The trouble started today.

You must have added something, either a test or something in the code being tested, that checks ARGS.

This kind of action-at-a-distance is why I think it's a good idea to make configuration (or other resources that aren't effectively-constant) explicitly passed in rather than global and implicit.

1 Like

Yes, I did!
The flag("e") thing refers to ARGS. I have to remove the function from tests...

UPD

Bingo! :smile_cat:

I normally interpret these situations as my code telling me I need to refactor/redesign because it is untestable.

A better solution would be to restructure your code so it passes configuration around via function arguments instead of globals. That way you don't leave your code untested, while also giving the test control over which arguments it uses instead of the arguments being fixed for the entire cargo test run

5 Likes

Sure :blush:

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.