unit-testingtestingrustassertconditional-compilation

Is there a way to specify assertions that would be active in tests only in Rust?


I am implementing a data structure with an inner invariant that I want to cover by tests. This invariant is a part of the data structure; thus, if implemented properly, it could never be violated by any sequence of actions of a data structure user, but I obviously still want it to be tested.

Currently, I simply use debug_assert! to test invariants, and my code looks like this:

fn test_invariant(&self) -> bool { 
    // some computations
}

fn some_algorithm(&self) {
    // some code

    debug_assert!(self.test_invariant());

    // more code
}

However, since test_invariant is somewhat computationally expensive and should never trigger in user's code, I want the assert to be active only in my own tests. Also, the invariant is a part of the algorithm, and so the assert could not be easily moved to unit tests (you can think of it as testing the heap invariant while implementing an in-place version of heapsort). Is it possible to do it in Rust?


Solution

  • As written, the test_invariant method will only be invoked in debug builds. That is, the expression in the argument will not be evaluated at all in non-debug builds, which is different from the behaviour that you'd see if debug_assert was a function rather than a macro. This is usually what people want, since production binaries will be a release build and tests use debug.

    If you are concerned about very slow code making it impractical for you to run debug builds, you could make your own macro that is conditionally defined, depending on if you are in tests or not:

    macro_rules! test_assert {
        ($($tt: tt)*) => { 
            #[cfg(test)]
            assert!($($tt)*)
        }
    }
    

    The test_assert! macro will behave just like debug_assert! except will only do anything in tests.

    Usually, though, it's much clearer if test assertions are done explicitly in tests where possible.