9

I can use cfg!(debug_assertions) to check if the Rust project is running in development mode, but I'd like to know how to check if a test is being run. Is there a similar flag for tests I can use in an if statement?

The reason is to prevent database writes while running integration tests.

Will Squire
  • 6,127
  • 7
  • 45
  • 57
  • Relevant: https://stackoverflow.com/q/55995061/1233251 – E_net4 May 20 '19 at 08:41
  • Why don't you have a trait for the database operations that has 2 implementations: a mock, and the production operations? – Boiethios May 20 '19 at 08:41
  • @FrenchBoiethios I do, and that's why I'd like to detect which one to use by detecting if it's running in a test. Also I don't mock because it would make it less of an integration test. – Will Squire May 20 '19 at 08:58
  • @E_net4 can that be used in an `if` statement? I.e. `cfg!(test)`. I've not tried it – Will Squire May 20 '19 at 08:59

1 Answers1

17

You can use cfg!(test):

if cfg!(test) {
    // do test stuff
} else {
    // do non-test stuff
}

However, this can lead to fragile code. For example, you might accidentally not execute some code in production, even though the tests all pass. It is often more robust to switch code at the item level, which would result in a compile error if you get it wrong:

#[cfg(test)]
impl Write for DB {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        // test stuff
    }

    fn flush(&mut self) -> Result<()> {
        // test stuff
    }
}

#[cfg(not(test))]
impl Write for DB {
    fn write(&mut self, buf: &[u8]) -> Result<usize> {
        // actually write
    }

    fn flush(&mut self) -> Result<()> {
        // actually flush
    }
}

If you forget to implement the not(test) version, you will get a compilation error.

Peter Hall
  • 53,120
  • 14
  • 139
  • 204
  • 1
    That doesn't work for me. Did you test this? I'd be curious to know if it works for you – Will Squire May 20 '19 at 10:17
  • Yes, it works for me, – Peter Hall May 20 '19 at 10:19
  • Are you running it with `cargo test` and is this via the unit test convention or integration test convention? – Will Squire May 20 '19 at 10:22
  • 1
    Try in the playground: https://play.rust-lang.org/?version=stable&mode=debug&edition=2018&gist=38b1ecd1cde65003406dafd600bdb400 – Peter Hall May 20 '19 at 10:26
  • 6
    Hm, I don't think this flag is getting set using the [integration testing](https://doc.rust-lang.org/rust-by-example/testing/integration_testing.html) convention. The example uses private functions, so it can't be testing externally as a `lib`. – Will Squire May 20 '19 at 10:35
  • 6
    It seems `cfg!(test)` doesn't work with integration tests – soulmachine Jan 02 '21 at 23:37
  • This chapter explains that it won't work for integration tests: https://doc.rust-lang.org/book/ch11-03-test-organization.html – Guy Jul 26 '21 at 17:40
  • You could use the `CARGO_BIN_EXE_` env var to check if you're running in an integration test. For unit tests, though, `cfg!(test)` is a great solution! – MPlanchard Nov 02 '21 at 16:53
  • Can't edit my comment, but noting the above only works for integration tests for binaries. Don't know of a way to figure out if you're in an integration test for a library. – MPlanchard Nov 02 '21 at 19:05
  • I'm relying on scripts to run my integration tests, so what I've been doing is passing an environment variable and I detect whether that env variable is set. Wish there would be a more universal method though – Christophe Vidal Jul 04 '23 at 06:49