Sometimes when we write a system test, it looks like this:
Sure, we're ending up with the test we want - scratching our back - but it's hardly direct. We're having to work ourselves really hard to get to an end result. See that window? We're standing there, spraying water trying to make the back scratch. That seated gentleman? He's your web server. Only if he's working right will we get to the breaking glass that's the responsibility of our app server. And only if the app server is also working properly will we eventually scratch our database back. Phew!
Wouldn't it be better if we just did this?
If we want to test scratching our back, we should test scratching our back. System tests (aka end-to-end tests) have their place; it's useful to know that all the pieces line up together. If what you're testing, though, is some inner piece of functionality, you can choose to address it directly with tests.
Directly testing a component:
- Allows us to provide better coverage with smaller changes (just move our hands around, not construct all sorts of variations)
- Creates a test with fewer dependencies, which is therefore easier to run and maintain
- Is more reliable because fewer things have to work to even get to the test we're interested in
- Is more maintainable because it's less susceptible to changes in the behavior of the other parts of the system between us and the behavior we're addressing
So if you're looking to thoroughly exercise a component, test the component as directly as possible. Save your system tests for testing the entire system and how it works together.