Reputation: 91
I'd like to be able to check within my code itself whether or not it is running from a test. It would be ideal to do this, for example, to interface with test databases, web services, etc. A simple bool
would suffice.
Does Rust have an existing API for this?
Upvotes: 6
Views: 2038
Reputation: 432109
There's no global variable that is set when running tests. You could add one, but it's pretty complicated to get it right. This example does not get it completely right:
use std::cell::Cell;
thread_local! {
pub static IS_TESTING: Cell<bool> = Cell::new(false);
}
fn my_code() -> u8 {
if IS_TESTING.with(|t| t.get()) {
0
} else {
42
}
}
#[test]
fn one() {
IS_TESTING.with(|t| t.set(true));
assert_eq!(0, my_code());
IS_TESTING.with(|t| t.set(false));
}
To do this correctly, you need to handle a few things:
More likely, what you want is to detect if you are compiling for tests. This is much simpler and you are probably already using the same technique to conditionally compile your tests themselves:
fn my_code() -> u8 {
if cfg!(test) {
0
} else {
42
}
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn one() {
assert_eq!(0, my_code());
}
}
Editorially, runtime or compile time detection is a bad idea from the perspective of code quality. Instead of littering your code with boatloads of conditional checks that will complicate and perhaps even slow down your code, introduce dependency injection:
trait ValueSource {
fn value(&self) -> u8;
}
struct ProductionSource;
impl ValueSource for ProductionSource {
fn value(&self) -> u8 {
42
}
}
fn my_code<S>(source: S) -> u8
where
S: ValueSource,
{
source.value()
}
#[cfg(test)]
mod test {
use super::*;
struct TestSource(u8);
impl ValueSource for TestSource {
fn value(&self) -> u8 {
self.0
}
}
#[test]
fn one() {
let src = TestSource(99);
assert_eq!(99, my_code(src));
}
}
This will concentrate related details into one object and the compiler monomorphizes the calls, producing optimized code.
Upvotes: 15