Fuzzing, e2e, property testing, & strict type system seem more worthwhile in my opinion.
Fuzzing, e2e, property testing, & strict type system seem more worthwhile in my opinion.
They also make the tests nearly unreadable and very hard to reason about IME.
For both of those examples you can:
1. Create a temp file in a temp dir and inject the tempfile (probably the name of the tempfile) into the object under test. So if your object edits and manipulates /etc/passwd you can create a real file with some passwd contents (or a built-in fixture checked into the tests) and then point the object at that instead of /etc/passwd. Then you don't have to mock the whole POSIX API. Since you create the file you can rely on it existing.
2. Write a minimal API which runs on localhost with minimal or no state, no threading, possibly no auth (although something elsewhere in your tests needs to test auth) or anything else, which your code can setup expectations and responses on then point the object at the "server". Since you create this service in your tests you can rely on it existing and it shouldn't be brittle.
For other objects you can expand the System-Under-Test (SUT) so that you construct multiple objects and feed them into the test. This is particularly true when the object you are testing sends messages to other objects and then expects to get changed state back out of them. Often better to just construct a real object rather than a mock. In a perfect world you might refactor everything so perfect unit testing was possible, but in reality you just won't be able to do this.
And in general, unit tests are often useless because of the mocking and because if the contract changes on one side and not the other then you wind up shipping broken code. They're fast, which is great, which means you can enumerate all of the edge cases, but some kind of functional/integration testing that uses larger bits of the system together is almost always better in terms of giving confidence that you're shipping code that works. And with an infinitely fast CI system I'd argue that you should never write unit tests and you should be spinning up real APIs in your test harness and hitting them with real client workflows.
Instead I write a lot of fast unit tests, although I'm real quick to jettison the idea that a unit test only covers one single object under test, and if the result isn't "really" a unit test, I'll let the philosophers sort it out.
I might be a wee bit lazy, but I’d just rather make 1-line implementation of interface-methods which ensures the behaviour I want to mimic.
Maintaining mocks in e2e tests often becomes infeasible with a meaningful amount of e2e tests.
Unit tests are valuable if you're writing something with a very well defined interface like a base64 encoder.
But bugs usually happen in the "glue".
Static checks and e2e pound for pound catch the most bugs with the least effort.