Reputation: 3432
I have a number of tests defined inside some of my modules with:
#[cfg(test)]
mod tests {
...
and a number of tests found inside my /tests
directory. All of these happen to need a common function called get_local()
that I have put inside a utils
module
+src
|-lib.rs
|-utils.rs
|-...
+tests
|_common.rs
Now since this function is only used in case I run tests I thought I should add a #[cfg(test)]
above it.
#[cfg(test)]
pub fn get_local() -> SomeResult { ... }
and then I make sure it is inside lib.rs
:
pub mod utils;
When I try using the function in tests/common.rs
though:
use my_crate::utils::get_local;
and run the tests with the test
command I get the error: no get_local in utils
. This error only goes away if I remove #[cfg(test)]
from the declaration of get_local
. Why does this happen?
Upvotes: 3
Views: 802
Reputation: 705
As for the "why does this happen?", Kevin Reid already answered: code in tests/
are "Integration Tests" and, therefore, uses the regular version of your lib (not the test-compiled one). See Integration Testing.
You may use the approach bellow to have a common test module for a single crate. Note that, for Integration Tests, each file inside tests/
is compiled as an individual crate. You may still create modules there.
With that said, my approach to having common test code is to put them inside a "test_commons" module and use:
lib.rs:
#[cfg(test)]
mod test_commons;
The contents of test_commons.rs has nothing special -- functions are defined without any #[cfg(test)] annotation.
Then, to use it:
#[cfg(test)]
mod tests {
use super::*;
use crate::test_commons::{self,ContainerKind,Blocking};
...
For Integration Tests inside tests/
to share that same code, simply use:
#[path = "../../src/test_commons.rs"] mod test_commons;
Upvotes: 1
Reputation: 43782
Why does this happen?
#[cfg(test)]
is only active when the crate is being compiled into a test binary (instead of a library or normal binary) — the same condition under which #[test]
functions are compiled to be run rather than ignored. But for a tests/
test, the crate being compiled in test mode is not your library — it's a separate binary crate for the test, which Cargo sets up to depend on your library compiled normally.
Thus, tests/
tests may only test the "public API" of your library — they see it no differently than a dependent crate outside your library.
As a workaround, you can use #[doc(hidden)]
instead of #cfg(test)]
so that the function is always available but undocumented, or you can put it in a module which is compiled into the test as well as the main library (but it's tricky to write code that works in both cases).
Upvotes: 2