Doctesting internals (sorta?)

Is this the correct way of doctesting internals?

#[cfg(doctest)]
pub mod git;
#[cfg(not(doctest))]
mod git;

The main reason we wanna do this is that this is an application and we want thin wrappers over various things (like git, sql, etc) so we can swap them out if we need to. In other words, the modules are basically treated like internal crates, and are used by other modules in the same crate.

2 Likes

I am guessing you are not talking of running the doctests on the items defined within the git module, since modules need not be public to be doctested.

So I am guessing that this is more of "how do I a perform an integration / doc test on an officially non-public part of my API"? And for that, the answer is indeed to use conditional compilation tricks to have these parts be public so as to be reachable by both integration and doctests.

The usual conditional compilation tricks are cargo features or cfg-blessed-through-build-rs-funneling env vars, but if, for doctests, #[cfg(doctest)] does the trick, then that's even better: it's well-readable and kind of clean, so it doesn't look like a hack much.

The only issue, of course, is that of the mod name duplication; in that regard, you can write:

#[cfg_attr(feature = "doctests", visibility::make(pub))]
mod git;

See:


EDIT: #[cfg(doctest)] does not seem to be a correct way to expose something to doctest code, as mentioned in the blog post that showcases it. Indeed, whilst there is a special scan of the code base to look for docstrings, and within them, code snippets to test, and this special scan is indeed affected by #[cfg(doctest)], the tests themselves are run by depending on the crate as a classic lib compiled with no special --cfg doctest whatsoever, similar to integration tests working on a code base with no --cfg test applied to it. So it does seem that even for doctests, the special feature or env-var-triggered custom cfg is needed.

1 Like