DEV Community

Discussion on: You should only write USEFUL tests

Collapse
robdwaller profile image
Rob Waller

It's an interesting post and I agree with your overall point about not being an ideologue and dealing with the world as it is. I do think there are some points to consider though.

  • High level tests aren't great at catching low level bugs and edge cases. This is because the higher the test the higher the path complexity.
  • Tests usually exist to prove your code works today and tomorrow. So while it may seem silly to write a test for func Sum(x int, y int) int { return x + y;} you may write a test or two to ensure this accidental change never reaches production func Sum(x int, y int) int { return x - y; }.
  • It's not the test's fault if the code changes. To prove code works tests have to be written, if the code later changes then so do the tests.
  • The reason change is often difficult is usually a combination of poor planning, business complexity, lack of resource and 'ambitious' timelines.
  • There are tools and metrics like mutation tests and CRAP scores which can help make writing tests, particularly unit tests, more focussed and efficient.
Collapse
destynova profile image
Oisín • Edited on

Tests don't prove that code works, though. They can only prove that it doesn't work, in specific circumstances, as well as provide some level of confidence that it probably works more generally. Property-based tests are a bit more powerful but it's not always obvious how to apply them.

I started using TDD in 2006 and found it quite refreshing, but I've also run into "mock hell" where your tests are ugly, verbose, highly coupled and brittle. These rarely deliver much value and are almost a tautology, since so much effort is spent to mock out the world so that what you're left with just makes an assertion that the method being tested is implemented a certain way.
In that sense I'd agree strongly with Douglas that many unit tests are written simply to agree with the code you've just written. This is why I dislike ham handed efforts to increase code coverage -- it leads to an inflated, low value set of tests that increases coupling and makes it less pleasant to make code changes.

Because of these limitations, I've become interested in lightweight proof checking systems that let you make general assertions about how your system behaves and have them checked automatically at compile time. One such system is Liquid Haskell which I find the most practical so far. However it's early days and still very far from mainstream, so I think we're stuck with unit tests for a while.

Collapse
robdwaller profile image
Rob Waller

If tests don't prove code works on any level or provide confidence then there really is no point in writing them. We may as well just accept software development is an unsolvable problem and users can just suck up the bugs.

In my experience all the problems with test, such as mock hell, have nothing to do with tests themselves. They relate to issues such as code design, data preparation and method complexity.

These issues mean there are more paths through the code which makes tests harder to write and means they prove little. But this is not the fault of the tests. It's the fault of the code under test.

As I said I'd definitely look at tools like mutation tests and CRAP scores to help with the non-test related issues which make testing more difficult.

Thread Thread
alainvanhout profile image
Alain Van Hout

The point isn't that test don't provide confidence. It's that they can only show the presence of bug, by virtue of failing when a given bug is present. But importantly, they only do that for the bugs that the implementing developer thought of. They don't show it fall for all possible bugs (unless the implementing develop thought of all of them, which isn't often the case).