Recently there’s been a great deal of discussion as to the merits of isolated testing versus integration and acceptance testing. Some proponents argue that integration testing far outweighs the value of isolated testing. While this is a perfectly valid position, I feel oversimplifies the complexity of testing in the same way that the “isolated testing only” crowd does.
Integration testing is wonderful for testing how components come together for a particular task. And it’s perfectly acceptable (and reasonable) to test how a model interacts with a real database, or to test how a controller interacts with the lower levels of an application.
What is missed in the discussion is the fact that unit testing (or isolated testing) can be and is useful for many different things. For example, testing an algorithm is a good use case for isolated testing. Mocking a database connection so that you can test database exception handling is another great use case. Testing classes with no dependencies (read: no other objects injected into them) is a another in a long line of use cases.
What often comes up in these discussions is the issue of mocking. The question that gets asked is, “if I’m mocking all these objects, am I really testing? Am I just testing my skills at mocking things?” The answer is yes – to a degree. It depends on why you’re mocking the objects.
Mocking objects that provide data can be useful. For example, if you want to test a specific type of data coming from a database, you can either create a database and seed it, or you can mock it. The choice is yours; I prefer to mock it as much as possible (to make my tests run faster).
But if you’re mocking objects and then giving them behaviors, you are really only testing your mock objects, and you should use real objects instead.
Finally, if you’re mocking half a dozen objects in your code just to make your tests work, you should think about refactoring; your object is probably doing too much in the first place.
So when would I write integration tests? Controllers make a great place to start with integration testing. They are the touch point for every layer of your application; take advantage of them. Integration testing complex SQL queries or complicated interactions is important too; isolated testing won’t highlight discrepancies between your components. I like to write integration tests to test that my database works correctly and that the seeded data makes sense. And integration tests that test an API are essential.
There’s a place in the PHP world for both isolated tests and integrated tests. Well-designed code makes isolated testing easy; that doesn’t mean isolated testing is the right kind of testing for that particular application or component. Instead, we should look carefully at the code we’re testing, and pick the right tool for the job.
Frustrated with your company’s development practices?
You don't have to be!
No matter what the issues are, they can be fixed. You can begin to shed light on these issues with my handy checklist.
Plus, I'll help you with strategies to approach the issues at the organization level and "punch above your weight."