4 ms·
All testing can ever do is increase your confidence that you’re delivering value and not destroying it. I think it’s easy to believe that if you’re just pure en
by thom 3y ago
All testing can ever do is increase your confidence that you’re delivering value and not destroying it. I think it’s easy to believe that if you’re just pure enough and follow some prescribed process or another then you’re doing a good job, but that’s just not possible. If you’re thinking about this stuff at all and you have some of your own principles, good on you.
Personally I’ve settled on this:
1) Whatever style of tests you write, they need all the love and attention your other code has. You need reuse, abstractions, constant refactoring. This makes me wary of external E2E frameworks in languages separate from your application codebase, but I’m aware most people don’t get to use a single stack across front and back end.
2) Functional tests are great. At the very least your codebase should have somewhere you can see its use cases enumerated (and preferably verified) and it’s rare for this to exist without functional tests (but good on you if you explicitly model use cases in your code). These are the things that actually make you money and should be your primary concern.
3) You can’t test every possible code path in functional tests, or at least not easily and quickly. I’m happy to test the bones of the system end to end but isolate complex logic the same way you would external dependencies. With this isolation you can easily write property based tests to verify the behaviour, and these to me are by far the most (dare I say only) valuable form of unit test.
4) I’m happy for end to end tests to hit mock/fake components but I always mock out the other side of the protocol. That is, tests that query a database always query a real embedded database not a mocked class that returns fake results. Embedded Postgres is extremely fast (20ms overhead in my tests) and perfectly reliable. The same is true of network services running in process on localhost.
5) Any time you mock/fake something you also need some way of verifying you’re not lying to yourself so you should have a minimum number of tests against real dependencies to verify your assumptions.
6) Unit test an implementation too early and you’ve done twice as much work to throw away when you refactor. You need to spike and stabilise based on your judgement. Personally I’m not concerned if I have no unit tests at all in code that is exercised by integration or functional tests, with the caveat about property based tests of complex logic above.
7) If you’re working on a legacy codebase or in a dysfunctional organisation then just do your best, obviously. Most of the time making things easier to test improves their architecture anyway but it’s very hard to pin revenue on that.