Tests/name.rs module does not see tests/name/submodule.rs

I'm refactoring my project to move away from mod.rs files. While this refactoring went smoothly for the src/ directory, I'm facing a problem when trying to refactor modules under tests/ directory.

The tests/main.rs contains references to sub-modules like tests/foo.rs which in turn should include tests/foo/bar.rs. However the last file is not visible from tests/foo.rs.

The source directory is as follows:

├── Cargo.lock
├── Cargo.toml
├── src
│   └── main.rs
└── tests
    ├── foo
    │   └── bar.rs
    ├── foo.rs
    └── main.rs

Runnign cargo tests produces:

   Compiling xxx v0.1.0 (/tmp/xxx)
error[E0583]: file not found for module `bar`
 --> tests/foo.rs:1:1
1 | mod bar;
  | ^^^^^^^^
  = help: to create the module `bar`, create file "tests/bar.rs" or "tests/bar/mod.rs"

For more information about this error, try `rustc --explain E0583`.
error: could not compile `xxx` (test "foo") due to previous error
warning: build failed, waiting for other jobs to finish...

After reading the book section on tests for a while, it seems that this kind of module naming is not supported in tests/ sub-directory, according to Test Organization - The Rust Programming Language.

Each file in the tests directory essentially acts as a separate lib.rs and crate, rather than separate modules.

If you want to change this, you can turn off automatic test discovery in the manifest and add an explicit test entry for a lib.rs or whatever main file, then use mod exactly like for the main crate.

Using mod shared; in multiple test files to mount the same module into multiple separate test targets is generally a bad idea, even though it's the most convenient way to share code between test files.

1 Like

Nitpicking: I would say that it is more like a main.rs, since it compiles to an executable (except that it is not required to have a fn main() unless you disable the test harness).

A different option is to respect the automatic structure. Cargo allows individual test targets to be multi-file; they just have to be in a directory (just like binaries in src/bin/). This structure should do what was wanted:

└── tests
    └── my_big_test
        ├── foo
        │   └── bar.rs
        ├── foo.rs
        └── main.rs