DEV Community

Discussion on: Doctests, the shy giant of testing modules

adambrandizzi profile image
Adam Brandizzi

Hey people, nice post and nice tips :)

Not every function warrants a doctest. Don’t bend over backwards trying to achieve 100% code coverage with your doctests. If that’s your project goal, use traditional unit tests to achieve most of your code coverage.

This is indeed the recommended approach. Yet, I'm doing something different and quite satisfying.

When I have a function not worth a test case, I'm writing doctests for it. This is perfect for internal functions: I do not pollute a module test suite with implementation details. It can also guide me on how to write the function (like TDD for smaller units) and the resulting function tends to be way better designed.

We all know those quite local pieces of code and thus never documented or tested. I always thought Doctest would be overkill there, but after experimenting, I feel it is right the opposite: doctests are the most lightweight way to document and test these units! And it proved worth the hassle: the docstrings have been very useful to explain how to use old code, rationales behind it, catch a lot of regressions and even improve the design. I wrote a post of how it works for me some time ago.

Of course, I'm not talking about the "right" way to doctest—quite the contrary, most doctesters work the other way around—but this is a possibility that a) helped me a lot and b) I'd like to see tried more.

perigk profile image
Periklis Gkolias Author

When you say'a function not worth a test case', what makes it need a doctest case?

Thread Thread
adambrandizzi profile image
Adam Brandizzi

Well, no function needs a doctest but, in my experience, it is useful to put a doctest in every function. Even the smallest private functions. For three reasons:

  1. We get documentation. With a doctest, we have a basic explanation of how we expect the function to be used, naturally. Even if the function is not published, it will be helpful when you're maintaining code that uses the function. And it helps a lot to reuse the code.

  2. We get some tests. The most basic behaviors of the function are now protected against unintended changes. If we have to handle a new corner case, we can add it to the doctest as well and ensure it will be preserved.

  3. And finally, the least obvious one: we get a better function. If we force ourselves to doctest a function, we find ourselves working to make it more documentable. Some lazy decisions we could take (relying on globals, mixing I/O and processing etc.) are not that convenient anymore. Our function got more and better seams, is easier to call and is more predictable.

Again, this is my experience after trying an unorthodox approach. Would you try it to be if it is true? :)