Unit tests for bin crate

I want to write some unit tests for functions defined in a project that is in a bin crate. But all the examples I see only show writing tests for functions in lib crates. Can I run tests in a bin crate by entering cargo test? If so, do I need to name the files containing tests a certain way? I'd really like to write doc tests in comments above my functions, but it really seems that only works for lib crates.

Yes. This will run functions with the #[test] attribute anywhere within your library and/or binary crates.

No. They can appear anywhere in src/main.rs or its submodules.

One way to make code more testable is to put most of it in a library (src/lib.rs) in the same package as your binary. Both doctests and the binary can then access public functions and types exported by the library crate, for example by importing them with use my_package_name::some_function;.

3 Likes

I haven't been able to crack the code on how to refer to the function I want to test. For example, I have this in src/lib.rs and when I run cargo test it says "cannot find function rank_name in this scope":

/// # Examples
///
/// ```
/// assert_eq!(rank_name('T'), "10");
/// ```
fn rank_name(rank: char) -> String {
    let rank = match rank {
        'T' => "10".to_string(),
        'J' => "jack".to_string(),
        'Q' => "queen".to_string(),
        'K' => "king".to_string(),
        'A' => "ace".to_string(),
        r => r.to_string(),
    };
    rank
}

I figured it out. I need to use the name from my Cargo.toml file which was "poker" like this:

/// assert_eq!(poker::rank_name('T'), "10");

I also needed to make the function pub which I didn't really want to do.

Doctests are primarily used as a way to document your crate's public API, so this is intended behaviour.

Under the hood, cargo will effectively create a temporary crate and copy the contents of your code block into it, adding your crate (and all its dependencies) to the temporary crate's Cargo.toml.

You should be able to use normal unit tests, though.

fn rank_name(rank: char) -> String { todo!() }

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn rank_of_t_is_10() {
        assert_eq!(rank_name('T'), "10");
    }
}
6 Likes