So you’ve built your app.
You’ve deployed it.
The client is happy.
Their users are happy.
You’re on top of the world.
And then, two months later, the client rings you up and says they need to change some of the existing functionality. Those pesky users have asked for an enhancement and it sounds like a great idea.
So you find your feature file and update the full stack test to reflect these changes. You find your steps file and update that to reflect the new scenarios in your feature. This is actually a difficult task in many applications, because a full-stack test needs to mirror what your application looks like in real life and so has load of setup data; at the time you write it, it all makes sense, but now, two months after you have no idea what’s what. I’ll revisit this another day, because it warrants an article of its own.
Now your full-stack test fails, as it’s got a load of new scenarios and steps that your commands no longer reflect. Time to get changing those too.
Open your text editor (I’m returning to Sublime Text at the moment, after years on Vim) and get editing.
But as your discovery tests use mocks and stubs to model the related objects they need to talk to, how can you be sure that they reflect the actual execution path through the app? How can you be sure that when you pass a
stub('client') to another object, it’s the same
stub('client') that the other object is expecting? Your full stack tests prove that it works – but because of complexity and speed restrictions we only cover a couple of execution paths through the code; we’re not testing absolutely every combination of functions and error conditions.
And this where your command layer’s dirty secret comes in to play.
If you’ve designed your application using discovery tests, each command forms a single node in a flowchart of functionality. Each node is deliberately really simple – making one or two decisions, then telling another command to do something.
Each command is small and simple. Each test is also small and simple. Each test is a discovery test. So just throw the tests away. You’re entering a new phase of discovery; a lot will be the same, but ultimately, your flowchart has changed, the commands that are interacting has changed and the data they send to each other has changed. So you need to start the discovery process over again.
This means you get the opportunity to revisit decisions you made in the past, which in the light of recent events may not have been the best. Your full-stack tests prove you’ve not broken anything. Your commands are only small, so you’re not losing much. And it makes you feel good – because you get to replace vintage code that you’re slightly embarrassed by with shiny new code that uses all you’ve learnt in the last few months.
And who doesn’t want to feel good?