Test submodule vs. private methods


#1

The idiomatic practice for unit tests seems to be to put unit tests in a “tests” submodule at the end of the file. Ok, sounds good.

But what if you want to unit test private functions/methods? Unless I’ve missed something major, private functions aren’t visible in a submodule, which makes the hard to test.

I’ve considered the following solutions:

  • Push private function tests out of the submodule. Seems like the best option.
  • Make everything public. Sort of defeats the point scoping.
  • Make them doc tests. I don’t want private functions in my documentation, and the code repetition involved is ugly.

Make me long for Euclid’s visibility rules. But is there a better option I’ve missed?


#2

Private methods are visibile in submodules.

fn f1() {}

mod foo {
    fn f2() {}
}

mod bar {
    fn f3() {
        // compiles
        ::f1();
        // does not compile
        // ::foo::f2();
    }
}

fn main() {
}

#3

Cool. Odd that none of the tutorials/blogs/documentation on testing mentioned this. Thanks.

Does leave one oddity: why does the reference to A in the submodule not work?

enum Bar {A, B}
use Bar::{A, B};

fn f1(b: Bar) {}

mod bar {
    fn f3() {
        // doesn't compile
        // ::f1(::A);
    }
}

fn main() {
    // compiles
    f1(A);
}

#4

Because ::A is not actually valid, even in the parent module. Try changing A to ::A in main to see.

My mental model here is that the use statement creates A in the current lexical scope as an alias to ::Bar::A, but lexical scopes do not propagate into mod-blocks, so if you want to use A unqualified inside the submodule you would need to say use super::Bar::{A, B} or use ::Bar::{A,B}. If you were to use a pub use instead of a simple use, then ::A would be created as an alias in the module namespace in addition to the lexical A alias; then use super::* would find it in the module namespace.

Disclaimer: I have not seen any code or documentation for this behavior, I’ve just done experiments.


#5

Is there a way to test private instance methods?

pub struct Foo {
    // some fields
}

impl Foo {
    fn f1() {}
    pub fn f2() {}
}

mod tests {
    fn f1_test() {
        let foo = Foo {};
        foo.f1() // this doesn't work
    }

    fn f2_test() {
        let foo = Foo {};
        foo.f2(); // this works
}

It would be ideal if it would be possible to test private instance methods the same way that you can test private static methods.