How to import a function from tests in another file?

I have a function in one module's tests that makes a big chunk of data. How do I reuse it in another module's tests?

// lib.rs
pub mod module1;
pub mod module2;

// module1.rs
#[cfg(test)]
mod module1_tests {
	use super::*;
	// other imports
	fn make_big_data() -> BigData {
		...
	}

	#[test]
	fn test_can_work() {
		let data = make_big_data();
	}
}


// module2.rs
#[cfg(test)]
mod module2_tests {
	use super::*;
	// whan import do I need here?

	#[test]
	fn test_module2_works() {
		let data = make_big_data();
	}
}

Your test modules are just the same as normal modules from an import perspective. Something like this will work just fine:

#[cfg(test)]
pub(crate) mod module1_tests {
	use super::*;
	
	pub fn make_big_data() -> Vec<u8> {
	    vec![]
	}

	#[test]
	fn test_can_work() {
		let data = make_big_data();
	}
}


#[cfg(test)]
mod module2_tests {
	use super::*;
	
	use super::module1_tests::make_big_data;
	
	#[test]
	fn test_module2_works() {
		let data = make_big_data();
	}
}

Playground.

Note how I changed the visibility to make it work.

1 Like

Still I can't import a function from test module in another file. In binary.rs, I try to import objects.rs::objects_tests::generate_my_struct. But no combination or chain of super/crate/<crate_name> worked.

Cargo.toml:

[package]
name = "modstest"
version = "0.1.0"
edition = "2021"

[[bin]]
name = "binary"
path = "src/binary.rs"

[dependencies]

lib.rs:

pub mod objects;

objects.rs:

pub struct MyStruct { pub a: i32 }

impl MyStruct {
	pub fn do_something(&self) -> i32 {
		println!("{:?}", self.a);
		self.a
	}
}

#[cfg(test)]
mod objects_tests {
    use super::*;

    pub fn generate_my_struct() -> MyStruct {
    	MyStruct { a: 4321 }
    }

    #[test]
    fn it_works() {
        let x = generate_my_struct();
        assert_eq!(x.do_something(), 4321);
    }
}

binary.rs:

use modstest::objects::MyStruct;

pub fn call_do_something(ms: MyStruct) -> i32 {
	println!("it's call_do_something");
	ms.do_something()
}

fn main() {
	println!("this is a binary");
}

#[cfg(test)]
mod tests {
    use super::*;
    // this doesn't work:
    use super::objects_test::generate_my_struct;

    #[test]
    fn test_call_do_smth() {
        let x = generate_my_struct();
    	assert_eq!(call_do_something(x), 4321);
    }
}

Across crates it would have to be pub mod object_tests, I suppose? (And use modstest::object_tests::…, not super::…)

1 Like

Oh, I guess I both misspelled a name and forgot pub. It compiles now, thanks!

So, the test example compiled. But I still can't get the real one working. I've thrown away everything, condensed it to this, but still it can't resolve the import:

$ cargo test
   Compiling modstest v0.1.0 (.../modstest)
error[E0432]: unresolved import `modstest::graph_tests`
 --> src/route.rs:7:16
  |
7 |     use modstest::graph_tests::make_graph;
  |                   ^^^^^^^^^^^ could not find `graph_tests` in `modstest`

Cargo.toml:

[package]
name = "modstest"
version = "0.1.0"
edition = "2021"

[dependencies]

[[bin]]
name = "route"
path = "src/route.rs"

lib.rs:

pub mod graph;

graph.rs:

pub struct Graph {}

#[cfg(test)]
pub mod graph_tests {
	use super::*;

	pub fn make_graph() -> Graph {
		Graph {}
	}

	#[test]
	fn from_edges_works() {
		assert_eq!(1, 1);
	}
}

route.rs:

fn main() {
	println!("!!!!");
}

#[cfg(test)]
pub mod route_tests {
	use modstest::graph_tests::make_graph;
    //            ^^^^^^^^^^^ could not find `graph_tests` in `modstest`

	#[test]
	fn do_something() {}
}

What is missing?

Shouldn't it be: use modstest::graph::graph_tests::make_graph instead of use modstest::graph_tests::make_graph?

I tried it that way before too, and just re-checked it again:

 --> src/route.rs:7:23
  |
7 |     use modstest::graph::graph_tests::make_graph;
  |                          ^^^^^^^^^^^ could not find `graph_tests` in `graph`

I've also tried adding pub mod graph_tests; to lib.rs, it didn't compile either.

Found a great reply on why this is not going to work when you try and import something from a library module that is #[cfg(test)] annotated in your binary. The unit tests in your binary are basically integration tests for your library (which you can see from importing from modstest::* instead of crate::*). This means when you compile your binary for testing, your library is compiled without the test modules.

Here is a post explaining much better what is going on that I just did:

If I were you and want to have make_graph available for integration testing (or unit testing your binary in your case), I'd put it in a module that isn't annotated with #[cfg(test)].

1 Like

That explains everything, thanks a lot! It also reminded me that there are benchmarks in cargo, I definitely need them.

1 Like

This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.