Cfg test does not work with integration tests

I am trying to build a basic terminal utility. This terminal utility uses Telegram bot API under the hood and I use clap to implement this utility.

Since the application uses real HTTP server to operate, I thought it would be better to mock the HTTP. Then I have found mockito and this amazing article showing how to test terminal applications.

I have tried to glue them together. Firstly, I get the API URL as below:

// related imports
#[cfg(not(test))]
fn get_base_url<'a>() -> &'a str {
    "https://api.telegram.org/bot"
}

#[cfg(test)]
fn get_base_url<'a>() -> &'a str {
    mockito::SERVER_URL
}

As you might have guessed, the first get_base_url function is compiled into binary when it is not test while the second one is compiled in testing environment.

I do not know if relevant but here is my integration test in tests/bot.rs directory:

#[test]
fn test_successful_authentication() {
    let _m = mock("POST", "/foo/getMe")
        .with_body_from_file("tests/resources/getMe.1.json")
        .create();
    let out = process::Command::new("./target/debug/tgcli")
        .arg("bot")
        .arg("-t")
        .arg("foo")
        .output()
        .expect("failed to execute tgcli");
    let out_text = String::from_utf8_lossy(&out.stdout);
    println!("{}", out_text);
    assert!(out_text.contains("Bot authenticated successfully."))  // fails here
}

Test fails on assertion. I have put a println! over there to see what the content is. Thanks to log and fern, I have seen what URL reqwest was requesting and it was the real API URL.

Do you know why #[cfg(test)] does not compile while running integration tests?

Thanks in advance.


Environment

  • cargo 1.40.0
  • rustc 1.40.0

Dependencies

[dependencies]
clap = "2.33.0"
log = "0.4.8"
fern = "0.5.9"
chrono = "0.4.10"
reqwest = { version = "0.10.0", features = ["blocking"] }
serde = "1.0.104"
serde_json = "1.0.44"

[dev-dependencies]
mockito = "0.22.0"

Your test is running the debug build of your binary as a separate process. It should work if you call the code directly that its running in that test function rather than spawning the binary as a separate process. There may be a way to call the test build of the binary, but I'm not sure what that is.

1 Like

Even if you fixed the issue of running the non-test debug executable, it still wouldn't work. See here for more details.

1 Like

Welp, that's a shame. :frowning_face:

There is simply no way to test my CLI application in this context then. I have also tried #[cfg(debug_assertions)] in some places but that didn't qiute work either (import errors).

You could expose functions that accept cli arguments as a list of string slices, and routes that through the normal argument parsing code?

1 Like

That seems viable. I'll try that.

If you have a function that takes clap matches and does the thing, you can construct the matches from a vec instead of the command line for for tests.

https://docs.rs/clap/2.33.0/clap/struct.App.html#method.get_matches_from_safe_borrow

1 Like

So I have finally arrived at conclusion that it will be better if I abstract away the functionality of my commands with independent functions and test these exact functions.

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.