At GeeCon Prague 2015, I saw a great talk by J.B. Rainsberger about integrated tests. It was basically a live version of his essay Integrated Tests Are a Scam, that I had read earlier. But It was great to hear his reasoning live, in a narrated way.
I use the term integrated test to mean any test whose result (pass or fail) depends on the correctness of the implementation of more than one piece of non-trivial behavior. J.B. Rainsberger
The Scam: Original Version
The gist of his talk (and his essay, which you should read), is: If you start to depend on integrated tests, you need to write more and more of them over time. Since they don’t put as much positive pressure on your design as unit tests would do, your code quality will suffer, more defects will escape your net of tests, and you’ll need more integrated tests to reproduce them.
The driving force here is: Positive design pressure caused by unit tests. We are missing this positive pressure with integrated tests, and this brings us into a tail spin.
The Problem with that Version
Now, some people seem to have a hard time to understand this narrative. After the talk, I have heard from several people things like:
“Integrated tests might not be the best possible solution, but they are not so bad. Better have some tests than none.”
“This sounds nice in theory, but I don’t think his solution (unit tests with mocks) will work in the real world. It is not any better than having the integrated tests.”
“But we have to test if all components are working together, don’t we?”
Some Don't Feel the Pressure
I almost dismissed what they said as “some people always complain”. But then I started thinking. For me, the reasoning in the talk was absolutely plausible and the conclusion to use unit tests and mocks seemed just right. Why was this not the case for other people?
And I think I found a possible explanation…
Some people don’t feel the positive design pressure from their tests. They write tests, but don’t take too much care to write good unit tests. Often, they don’t refactor enough. Then, after a very small change, 20 tests break, and they complain that testing is waste. I have seen this scenario, and I did those things myself.
In other words: TDD is hard. You have to learn it and train it and take the time to do it right. But when you do it right, you can get great benefits from it.
Alternative Version of the Scam
Even if you do TDD like that, integrated tests are still a scam: They still lead you down this vicious circle where you need more of them the more you have.
- We already have some integrated tests
- They don't catch many errors (because you never have enough integrated tests)
- When an error occurs, we try to write a test
- Since we already have some integrated tests, and we do not refactor enough, some parts of our system are really hard to test
- So, let's just add some code to an existing test or write another integrated test, and then fix the bug
- We have less time to write unit tests or improve our design
- Go to 1
I know that one can explain this cycle with “the positive design pressure is missing”. But it feels differently for the people in the cycle, who are not “listening to their tests” anyway. Because if they would, they would not be in this cycle.