What You Really Need To Know About Testing
Sometimes discussions on testing frustrate me beyond measure. They do because everyone is assuming so much on either side. They take for granted that the world shares their notions of the differences between a stub, a mock and a spy. They believe that the definition of a unit, functional, integration, acceptance or end-to-end test is obvious to everyone. They render common knowledge the fact that you should have X, Y or Z proportion of each type of test in your codebase. They battle about which testing framework to use based on their features, or what patterns to implement in their tests. Go developers still are battling between using test tables or just simple functions.
All this frustrates me. It does because testing discussions become focused on the details and not on the bigger picture and goal of testing.
The bottom line, tests are little programs that assert things about your code. There are only two main requirements for them: (1) they must run quickly and, (2) they must fail clearly and for useful reasons.
You might cover all of your applications with a Cypress suite, but then good luck running that on a CI: it will become your delivery bottleneck. Or try to hit the database in every single one of your tests that use PHPUnit: that's going to take a while to run. Tests are meant to give us feedback quickly. When working with a codebase, we need to know if we broke something with our changes. We can't wait 5 minutes for that.
Is of little use to have everything covered with integration or acceptance tests if every valid change to the codebase is going to break half of your tests. You need to think about what you are asserting on those tests. Assert structure and not just compare strings. Write validators if necessary for creating complex assertions more easily. Also, assertions need to be constructed to give the developer an accurate error message, so they can identify the source of the problem. Tests should fail clearly.
Again, make sure your tests run quickly and fail for useful reasons. Unit tests that overuse mocks tend to run very fast, but they fail often with valid code changes. Integration tests are a bit slower and rely on heavy dependencies sometimes, but tend to fail for correct reasons. End-to-end tests are expensive to run and very slow, but if you assert correctly about them, they can detect valid failures.
Find the test strategy that better adjusts to your team's knowledge and the kind of project you are working on. Once you have it, keep improving your testing suite by eliminating slow and flaky tests. That's all that matters really.
Did you find this article valuable?
Support Matías Navarro-Carter by becoming a sponsor. Any amount is appreciated!