Search code examples
unit-testingtestingrustbddrust-cargo

Is there some way to build Rust documentation that includes the test documentation strings?


Our testing methodology has test documentation as a first class object in the documentation output. Specifically, it defines the specification that is tested by each behavioural test.

Running cargo doc on a project with suitably documented tests doesn't yield much in the way of documentation derived from the test doc strings and I can't see any obvious way of making it include the test doc strings in the output.

An example module would be as follows:

/// This function does some important stuff
pub fn working_fn() -> bool {
    true
}

#[cfg(test)]
mod tests {
    //! This is some important set of tests
    //!

    use super::*;

    /// The function should work
    #[test]
    fn it_works() {
        assert!(working_fn());
    }
}

I get documentation output for the public working_fn, but nothing for the tests module. I appreciate that an additional complication is that tests are private and ideally I'd be able to document private tests without also documenting other private objects.


Solution

  • You can introduce a new feature flag that can be used to treat tests specially for the purposes of documentation.

    Add the feature to your Cargo.toml:

    [features]
    dox = []
    

    Use the feature flag in your code.

    1. Compile the tests modules if tests are running or the feature flag is provided.
    2. Only mark #[test] functions if the feature flag is not provided. The #[test] attribute automatically implies #[cfg(test)], so we have to skip that to allow the function to exist.
    /// This function does some important stuff
    pub fn working_fn() -> bool {
        true
    }
    
    #[cfg(any(test, feature = "dox"))]
    mod tests {
        //! This is some important set of tests
        //!
        use super::*;
    
        /// The function should work
        #[cfg_attr(not(feature = "dox"), test)]
        fn it_works() {
            assert!(working_fn());
        }
    }
    

    Build the documentation

    cargo doc --document-private-items --features=dox
    

    Keep an eye on #[cfg(rustdoc)], which would allow you to remove the need for your own feature flag but is currently unstable.

    See also:

    ideally I'd be able to document private tests without also documenting other private objects

    You could make your tests pub or pub(crate).

    If that wasn't an option, I think this will be more annoying than it is valuable. The direct solution I know of would be to follow How do I change a function's qualifiers via conditional compilation? to conditionally make the test pub or not.