Consider this (rather suboptimal) prime factorization algorithm: You can run it like so and see that it returns the proper factorization for a variety of Int32 values: In fact, it works properly for any possible Int32 — except one very…
The binary coverage hypothesis
Everyone loves to hate code coverage. But I have started to notice one interesting consequence of using coverage metrics that I refer to as the binary coverage hypothesis: A class should either have full unit test coverage or none at…
Nothing beats the real thing
One common pitfall when operating in a mock-heavy TDD context is the tautological test. This is especially true for code which involves awkward dependencies. “I want to avoid talking to the real [database|API endpoint|etc.] here in this class,” you say.…
Living in the test zone
I have previously written that, when given the option of many similar implementation strategies, you should prefer the one which is easiest to test. There is a simple corollary to this proposition: whenever possible, grow your codebase in areas covered…
Humble controllers
Whenever I write code using ASP.NET Web API, I invariably make my controllers “humble.” I use this term in the same sense as described in the Humble Object pattern. Basically, a controller should be a thin coordinator between the client’s…
Loopy tests
Loops are fundamental structures in almost every programming language (we’ll put aside APL for the time being). In unit tests, however, loops can be a problem. This is especially true of loops in the “Assert” section. For instance, consider this…
Efficient concurrency prevention
Sometimes you want asynchrony but not concurrency. For example, if you are writing data to a file, you should generally prefer asynchronous I/O, but you probably don’t want 10 other competing callers to corrupt the contents. Perhaps the simplest way…
Once is not enough
In the olden days of boxed software products, the “full test pass” was a borderline sacred ritual performed near the end of a release. Ostensibly, its purpose was to make sure all the product features worked as intended — for…
Destroy all* test environments
Test environments are a liability. Sometimes they’re so good, they’re bad. Though most of the time they’re just bad. So what then, do we just test in production exclusively? Obviously it’s not that simple and there is a more nuanced…
Code coverage is a legacy metric
In the words of Michael Feathers, legacy code is code without tests. My corollary to this is that code coverage is a legacy metric — best applied to these very same legacy systems with poor, inconsistent, or absent testing practices.…