Sharing test utility function between lib and bin

I'm trying to use a common test utility function between my library (in the src directory) and binaries (in bin). I'd rather not expose this function outside of the tests, but it seems like the unit tests in the bin directory don't have access to the test modules in the src directory.

For example, my directory structure looks like this

project
|--bin
|    |--my-app.rs
|
|--src
     |--lib.rs

and my lib.rs looks like this:

// lib.rs
//
// Code here
//
#[cfg(test)]
mod tests {
  pub some_utility() -> String {
    "Hello".into()
  }
}

and my-app.rs looks like:

// my-app.rs
//
// Code here
//
#[cfg(test)]
mod tests {
    // Gets "unresolved import"
    use project::tests::some_utility;

    #[test]
    fn some_test() {
      let foo = some_utility();
    }
}

Now, this all makes sense to me - if we're treating my lib like it's an external crate, then I shouldn't have access to its test utilities, but I'd like some way to have this kind of test utility sharing without having to duplicate the code in two places.

Thanks for any help,

-Jack

You might want to extract it to its own small crate if you think it's general enough. Also, try considering the case where someone else makes a different wrapper around your library, perhaps it exposes a C interface or web interface or something. Would they need access to this test utility?

It's not really that general, or that useful outside my tests.

It's really just that I do very similar things (e.g. constructing a random name for a unix socket path) in the unit tests for both the binaries and the library, so I'd like to refactor that into a single function that both can call.

The alternative is to replicate the same function in both places, which I can certainly do, but which seems kinda dopey.

-Jack

You could use something like this to include the same module in both places. This has the same effect as duplicating the code, but without having to actually maintain two copies:

#[path = "../src/test_utils.rs"]
mod test_utils;

(I normally wouldn't recommend doing this, but for test-only code I think it's fine.)

1 Like

Oh, nice, I didn't know about that.

I can definitely understand your hesitation, but, yeah, it should be okay in tests.

I'll give that a try! Thanks!

-Jack

@mbrubeck that worked really nicely, thanks!

I'd still kinda like to know if there's a more "standardized" way of doing this, if such a thing exists, but, honestly, this works just fine.

Thanks again!

-Jack

If instead of putting your binary in bin/my-app.rs you put it in src/main.rs, you should be able to just use mod test_utils; without the path qualifier in both places. (This definitely works in main portion of code, not 100% sure this works in test)

Edit: Never mind. That doesn't work.

You'd have to do something like this
src/util.rs

pub(crate) foo() {
}

src/lib.rs


#[cfg(test)]
mod util;
#[cfg(test)]
mod tests {
    use super::util::foo;
}

src/main.rs

#[cfg(test)]
mod util;
#[cfg(test)]
mod tests {
    use super::util::foo;
}
fn main() {
}