DEV Community

Filip
Filip

Posted on

5

What's up, doc? Rust doctests and you

Rust has an interesting feature in its documentation system: if you're writing a library, it will actually compile and run the examples you give in your rustdoc comments as tests. This took me by surprise because I typically don't expect the documentation examples to immediately work, but I see why this is being done - and it's all to do with the fairly obvious: people will copy and paste examples from docs into their code.

Advanced Copying And Pasting From The Docs

So, doctests try to ensure that the examples you give in your doc comments will actually work. Cool, how do we make use of that?

Denial: Not a river in Egypt

You can ignore doctests. Sometimes you may just want to let an example be an example and not be considered a test.

/// Adds two numbers together:
/// ```ignore
/// add(2, 3) == 5
/// ```
fn add(a: i32, b: i32) -> i32 {
return a + b;
}

Acceptance: Let it go

You can also just let doctest run your code examples. What you need to keep in mind is that you will need to use all your types inside the example, like so:

/// Adds two numbers together:
/// ```
/// use doctest_test::add;
/// add(1, 1);
/// ```
fn add(a: i32, b: i32) -> i32 {
return a + b;
}
view raw simple_run.rs hosted with ❤ by GitHub

Enlightenment: Writing examples as tests

Tests in Rust are fairly simple - any function that either returns () or panics can be a test, and your doctests can be used as regular tests, with asserts and everything:

/// Adds two numbers together:
/// ```
/// use doctest_test::add;
/// assert_eq!(add(1, 1), 2);
/// ```
fn add(a: i32, b: i32) -> i32 {
return a + b;
}
view raw test_run.rs hosted with ❤ by GitHub

Galaxy brain: hiding the tests in your docs

But what if you don't actually want to put all the test code and boilerplate in the documentation example itself? Well, rust has you covered too:

/// Adds two numbers together:
/// ```
/// # use doctest_test::add;
/// let c = add(1, 1);
/// # assert_eq!(c, 2);
/// ```
fn add(a: i32, b: i32) -> i32 {
return a + b;
}

And note how this will look in the generated HTML docs:

The last example doesn't show the boilerplate code

(Also see the little warning label on the first example? That's because we marked the first example as an ignored test, and the docs will make a note of that - so that's an incentive to keep your doctests passing.)

Even more

Those are just the basics of doctests in Rust, and if you write libraries in this language, you should definitely check out the documentation tests manual for more - and I bet those examples are also tested 🤯

Image of Datadog

The Essential Toolkit for Front-end Developers

Take a user-centric approach to front-end monitoring that evolves alongside increasingly complex frameworks and single-page applications.

Get The Kit

Top comments (1)

Collapse
 
jeikabu profile image
jeikabu • Edited

Good write up on Rust fundamentals.
I have a love-hate relationship with the current state.

I do love the idea of testing documentation examples.

I'm less than thrilled about some of the current tooling:

  • With VSCode and RLS, at least, no syntax highlighting and no Intellisense
  • Using ?/Result is clumsy
  • compile_fail is useful to show correct ownership usage, but since you can't specify the failure type unrelated failures also cause the test to pass
  • IIRC, test failures aren't helpful; think it mentions the line number in the test instead of the line in the file, and maybe doesn't have the filename

There's other comment formats that can be helpful. For example, to write a multi-line module doc test:

/*!
## Tests here
*/

A Workflow Copilot. Tailored to You.

Pieces.app image

Our desktop app, with its intelligent copilot, streamlines coding by generating snippets, extracting code from screenshots, and accelerating problem-solving.

Read the docs