I like unit tests for testing my web services. They’re fast, and they give me confidence that a little bit of code does what I think it does.
I like integration tests for testing my web services. They test the way my pieces interact with each other in ways that unit tests can’t, and give me confidence that my app behaves correctly in general.
I keep trying to shoehorn my test suites into one or the other. I think this is a mistake. Unit tests should isolate functionality, stub or mock dependencies, and quickly determine that the smallest possible piece of functionality does the right things in the right order. To some extent unit tests often end up verifying implementation details, and I think that’s okay. The nature of a unit test is such that you should have a lot of them, and high coverage as a result. However, this form of coverage is well-known to inadequately represent the “testedness” of a system, and the reason is that they do not measure how many of your contracts were exercised. Was this function called with one argument, with two, with three, with four? Was it ever passed
null? Could it have been?
That’s where integration tests come in. But these require you to spin up your app, wiring resources, making http requests, possibly hitting a local database… it might take a long time. This is why you should design your integration test strategy such that you exercise each interaction between your components. Don’t worry about testing every feature. It turns out this will force you to create at least one happy and unhappy path test for each of them anyway. But you might find that your current test suite is following the same path very often, so much so that its only difference from an equivalent unit test is that it verifies something that your other integration tests are already verifying.
Now go write some tests. Just, not too many.