[SOLVED] Importing modules into test files

Modules is a strangely difficult thing to grasp in Rust. I have shuffled things around quite a bit in my project to familiarize myself with all the different ways of using/moding. However, it still is not clear to me even after reading the docs on modules. I have used the compiler to help me up to this point but I am stuck on how to import my functions into my test file. My directory looks like this:

src
├── channels.rs
├── data
│   ├── channels-all-time.json
│   ├── members-all-time.json
│   └── overview-all-time.json
├── main.rs
├── members.rs
└── util.rs
tests
├── channels.rs
└── data
    ├── channels-all-time.json
    └── members-all-time.json

My helper functions exist inside of mods inside of members.rs, util.rs, and channels.rs. I can't for the life of me figure out how to get them into tests though. When I try to import my module by doing use channels in my channels.rs file under tests I get this error:

error[E0432]: unresolved import `channels`
 --> tests/channels.rs:1:5
  |
1 | use channels;
  |     ^^^^^^^^ no `channels` external crate

When I use main I get a slightly better error.

warning: unused import: `main`
 --> tests/channels.rs:1:5
  |
1 | use main;
  |     ^^^^
  |
  = note: `#[warn(unused_imports)]` on by default

This gives me a little hope thinking that because I put mod channels in main.rs, maybe that means I can import them from there so then I put use main::channels. But to no avail:

error[E0432]: unresolved import `main`
 --> tests/channels.rs:1:5
  |
1 | use main::channels;
  |     ^^^^ use of undeclared type or module `main`

Any help on this would be appreciated. I know I am missing something but I can't quite wrap my head around it.

Integration tests can't import anything from the binary, only from the library. That's one of the reasons to have main.rs as a thin wrapper around lib.rs and not as an independent entrypoint.

I wish I knew what this means :frowning:

When you create the package, there are by default two files considered as "main": main.rs, which is the entrypoint for binary crate, and lib.rs, which is the entrypoint for library crate. Each of them can declare its own tree of modules, both can use any dependencies, and, furthermore, the library crate is listed as dependency for the binary one: i.e., use can use crate_name::module_name; from main.rs if module_name exists in lib.rs.

The approach I'm speaking of is like following. Instead of having the business logic in main.rs, you move it entirely into lib.rs. The function main in main.rs would simply call the corresponding function in lib.rs (possibly validating program arguments or something like this).

Considering your question about tests - they should treat your library as dependency, too, and simply use crate_name::channels.

2 Likes

Thanks @Cerberuser! This is what I needed. I did just as you said and put my functionality inside my lib.rs and exported it to main.rs. Now I can actually run tests and the pieces of functionality that exists in lib.rs.