How to organize code for proptest?

I have a code organization issue and would like to know how others usually deal with that. I'm trying to use proptest and creating a function to generate strategies for some type of mine:

fn strategy() -> impl Strategy<Value = Foo> { ... }

I can implement that function in two ways, either only using the public API of Foo or using private implementation detail. I prefer using the private API because it will generate much better values for property testing. Using the public API would really hurt the testability since it requires a oneof! and covers only a small subset of the possible values without using other functions that are heavy etc. Basically I need to use the private API for the implementation of strategy().

But the tests I want to setup only use the public API of Foo so are better located in integration tests folder tests/. Ideally what I'd like to have is something like the following:

// lib.rs
#[cfg(test)]
impl Foo {
    pub fn strategy() -> impl Strategy<Value = Foo> { ... }
}

// tests/foo.rs
proptest! {
    #[test]
    fn test_foo(foo in Foo::strategy()) { ... }
}

But the issue is that the things under #[cfg(test)] in the lib code do not seem to be available in integration tests. An easy solution would be to remove the cfg(test) but proptest is only in my tests dependencies and I'd like to avoid putting it in the normal dependencies. Otherwise I could put everything in unit tests, but they don't really belong there.

How would you deal with that?

Concretely, the Foo type above is Range defined here in case that helps: https://github.com/mpizenberg/pubgrub-rs/blob/master/src/range.rs#L23 and I'd like to do property testing to verify that intersection, union and complement of sets verify few properties.

It seems if you can't get your integration tests to have #[cfg(test] you could have a look into the less used visibility modifiers pub (in crate::..., pub(super), shown in

And see if one of those wouldn't work to make it public, within some module, and perhaps you would need an empty stub of that module for cfg(not(test)). Not sure, never run into this.

1 Like

It seems I can put things in #[cfg(test)] in integration tests but they don't get access anyway to things in #[cfg(test)] in the lib code.

Thanks for the link to visibility modifiers. I think for now I'll just put everything in the library module. It does the job and isn't too bad, but I was wondering if there was another option to strongly indicate that those property tests do not use any private impl detail (well except the generation of the input data for those tests ^^).

The things in #[cfg(test)] in the lib code are not included in the "genuine" builds of the lib, which is what you link with for integration tests, and as you wrote earlier, that's actually what you want from integration tests.

I don't know how, but I think the only way is to define the property based tests as unit tests. You cannot keep the unit tests out of the private parts of the main module, but they cannot access stuff in private submodules, so perhaps with a fake parent module for testing only that re-exports the public API you can get there. Or with feature flags, as in:

1 Like