A while ago I was asked how to handle the case where setting up unit tests became complex because you wanted to test at a lower level. Since that question itself confused me I tried to understand the problem and it turned out that person started by writing a test for some high level abstraction faking all dependencies. Once that was done he then tried to fake some lower level dependency using a real middle implementation and still calling things from the highest level. When I explained how he should think instead we came up with what we ended up calling the TDD stairway in our discussions. Take a look at the image (click on it for a larger version).
To the left i have just made up a number of abstraction layers you may have in your application. The blue arrows represent where your test code should make the call, i.e. how you invoke your code. The yellow boxes indicate parts you need to fake. The green boxes represent the code being executed in each case. As you can see you first have a three step stairway with unit tests (UT). When writing the unit tests you always have your test code pretend to be the abstraction above the code you want to test and you always fake the abstraction below the code you want to test. This is the kind of tests you should be writing when you do TDD/BDD.
At least most of the time. Because sometimes it makes sense to write an integration test that uses the real thing all the way. These integration tests may be written by your test team if you have one but most of the time I think they would be written by the same person who write the unit tests. The interesting aspect of the integration test is that it uses almost all abstraction layers and may have a fake at the bottom.
Then there are also end-to-endtests (or scenario tests or acceptance tests or whatever you want to call them). These use the real thing all the way. No faking and no shortcuts! This is definitely something you'd have a separate test team working on.
And as ususal, no matter what type of test you write, you want it to be automated. Anyway, back the the stairway... I think it explains pretty good how to think when deciding what to test and how to test it (and what to fake) at different levels of abstraction. I've used this analogy multiple times and it seams to work pretty well so I wanted to share it. What do you think?