Have you ever gotten so frustrated when writing a unit test that you gave up and wrote an end-to-end test instead?
It seems to me that this is one reason why people prefer end-to-end tests over unit tests: because unit tests can be difficult and frustrating.
But this is precisely why unit tests are useful: unit tests give you design feedback.
If your unit test is hard to write, then that’s a good thing: the test is telling you that your design can be improved.
When you’re faced with a hard-to-write unit test, the solution is not to rewrite your test to be an end-to-end test. The solution is to refactor your production code until the unit test becomes easy to write.
A unit test is like a clamp that holds your system in place while you refactor around it.
If you’re puzzled as to what I’m talking about, then perhaps you would do well to read a book like Kent Beck’s Implementation Patterns or 99 Bottles of OOP by Sandi Metz. (And if you’re a React developer, consider reading my book, Mastering React Test-Driven Development.)
Most developers are well aware of how to make their own code simpler. And yet they don’t do it.
Very often, developers don’t have enough trust in themselves to refactor safely. They fear causing unexpected regressions. They worry that they’ll spend all day refactoring and they won’t make progress on their assigned work.
If that’s you, try giving unit testing another go. Listen to the tests and let them give you the structure you need to make positive change to your codebase.