Documentation + Tests in Rust
When spending time on medium, developers talking about Rust appear to only really want to show their understanding of the borrow checker…
When spending time on medium, developers talking about Rust appear to only really want to show their understanding of the borrow checker, but I will put to you that this is not the only great feature of the Rust ecosystem.
The ecosystem has a fantastic handle on the partnership between code, tests, and documentation.
The borrow checker gives most green rustaceans a run for their money, for sure. It is quite obvious that the next step when someone thinks they have a good handle on it to share that information with others — I know this not just because of the frequency of such posts but because I too thought about doing the same. Surely someone else is having problems like I did.
What about two things engineers don’t value, so often? Documentation and testing are commonly overlooked and occasionally argued over elements that green and seasoned engineers don’t agree upon.
- Should you test everything?
- Should you write unit tests?
- Should you document your code?
- Should you write self documenting code?
Such questions come up often and typically end in a subjective response based on someone’s political beliefs.
But instead of trying to argue the point, what if we just agreed that documentation and testing were important, for the purposes of this article?
Yea? Commenters? Lets not have that argument.
Thanks =D
Code in Rust is new, finicky, and drawing a lot of attention as the ebbing and flowing of programming language news does its thing. So many people are bringing up the idea of rewriting huge chunks of their favorite project in rust at this point that its a meme. Programmers seem to want to turn their whole lives upside down because Mozilla/Firefox are doing great things.
On the whole, one might be willing to share the belief that documentation tools haven’t come a long way, and largely I would agree. From the days of having to comb through CPAN to figure out which module I can reliably trust to provide web navigation and parsing functionality for automated testing needs I remember thinking that the documentation world blows. So much wasted time spent trying to understand why when an example is copied into my project it doesn’t produce the expected result. So many hours and days spent trying to understand why documentation tools seem to be broken.
Why not do something to spice things up? Why not do something to bring documentation and examples out of the dark ages?
Making Waves
At first glance, developers acquainted with Doxygen, JavaDoc will feel at home. The documentation tool in Rust is largely the same old syntax doing the same old job to ultimately result in an html render of your code’s inline documentation. You can comment and annotate functions, traits and the like just as you would in any of the sister implementations.
You can use YA version of Markdown that seems to be inline with the version used on GitHub to help with formatting and maintaining stylistic choices, and when you need to include code examples you wont feel like you are out in left field.
You will see some ridiculously simple documentation generated from the generated library, but note the path because from this point forward you will need to repeat the cargo doc
and refresh this html page process as you work if you want to check your work as you go.
Go ahead and document your code, then come back. Add some code examples like this and render things:
Note that it recognizes many languages, but also that it renders the code blocks using syntax highlighting, which is fantastic. Big win there and we haven’t even gotten to the best part.
Two months down the line you come back to this module and make some modifications to support your new requirements. You add a new function called meaning_of_life which under all circumstances will always return the answer 42. For illustrative reasons lets pretend that you aren’t a stickler and you don’t bother updating your documentation.
This is what is output on the command line when I execute my test cases and documentation steps:
That’s about how things typically go. In other documentation tools we would push things public and call it a day. Problem is that our documentation is out of sync. The example in our documentation is still doing that dumb tautology and not validating our code.
What if we could raise the bar? What if our code examples were tested? What if we could run those same code examples as test cases to ensure they are validated when we test our code?
Go ahead and play with meaning_of_life
and watch how running your test cases now results in failures not just in your inline unit tests, shown here at the bottom of my file, but also in your documentation test cases.
One noteworthy element is that you might find this to be too verbose for a reader, as in they should not need to see your code and assertions in the documentation. There is a simple modification you can make in this regard to improve the usability of your code examples — prefix anything you dont want a user to read with a #
and run your documentation task again.
All and all this is probably my favorite feature of the ecosystem, though borrowing is also neat once you get it.
For some hands on testing and building up the notes I used for this article I build up the human_format library. For more information about the documentation tool and its features you may want to take a look at rustdoc, or take some time to pop over to docs.rs and see what neat examples you can find.