- Refactoring Without Good Tests - Code Climate Blog
- A Better Syntax For Unit Tests - Andrew Binstock, Dr. Dobb's
- Agile Moments, "Why We Test" Edition - Eugene Wallingford, UNI
среда, 11 декабря 2013 г.
TDD: Tests are for Focus
In recent posts I have written much about testing as an inherent component of the software development process – the last one, for example, was devoted to some drawbacks of having tests. Now, to keep things in balance I will turn to an advantage of TDD which I happen to mention much less frequently than it deserves.
When writing tests I do search for such things as confidence, correctness of code, guidance for better design and description of the software components and their invariants – all the things that I come back to in each and every post about tests. As I wrote a couple of weeks ago, with all this I get some inertia and a chance of falling into the trap of overestimating the quality and bugproofness of my programs for free. Still, tests give me one more gift, which is sometimes more valuable than all other benefits and compensates for many drawbacks: tests make me focus on doing precisely what I need to do at a particular moment and think solely about it. Put another way, they allow to work on features one at a time, ignoring most of the context until the current portion of work is finished. This undoubtedly positive narrowing of scope is done in two ways – passive and active, if you wish.
To begin with, if one uses the tests-first approach, each unit test, once it is created, acts to draw developer’s attention to a certain small piece of functionality – the piece that is desired, but missing at the moment. When you strive to make a test pass, the red light does its best to help you focus on solving this particular problem. In fact, if you are disciplined enough to start writing tests, you are also most likely disciplined enough to devote all your efforts to making the single test go green, instead of going elsewhere and hacking code that does something valuable though irrelevant at current stage.
Beside the annoying red light that obliges a programmer to do what it wants, there is another thing to unit tests that helps one to concentrate. It is difficult to clearly separate this from all the benefits that I usually mention, but tests make the task of starting a component or even the entire project much easier. From my perspective, that happens because of the combination of two causes. First, to make up even a single good test you have to chunk your work explicitly. The act of fulfilling this requirement has a well-known name – that’s simply planning. This said, when laying out a test-suite one actually writes a plan of a particular unit of their program providing themselves with two key components of every plan: explicitly named goals and the means to know when one is done with them. Everyone who has tried to create a schedule for a week at least once knows for sure that plans hold much value and large part of it comes from availability of a carefully laid list of tasks, which draws one's attention to their goals and helps a lot to focus on them. Let me repeat it once more: tests are your plan, roadmap showing where your program can be driven.
Another reason that makes programming with tests easier is that, in my opinion, composing test cases is often less difficult than implementing actual components. Since tests play the role of usage scenarios their idea might be clearer than the details of how certain goals should be achieved – at the beginning we usually understand what we want from our programs better than what should be under their hood. This way, tests written by a programmer actively help him or her focus on development. However, that’s only the active part of the story.
The idea behind the passive influence of testing on programmer’s concentration is actually much clearer and boils down to a single word – regression. As we know the key purpose of regression testing is to verify that new code doesn’t break the existing functionality. More accurately, when regression tests are run they automatically check that certain assumptions about the system still hold despite the arrival of new chunks of code. This ability to know when you have stepped the wrong path and broken something is important enough by itself, but what makes it even more valuable is the fact that it frees you from worrying too much about the possible far fetching impact of the fresh code that you commit. The attempts to foresee the surprises, which a minor change in the existing code can bring, take a lot of mental effort and make it very difficult to focus solely on working to your current goal. Our mind is powerful, but it doesn’t allow to concentrate on several things at once, so it is quite good to be able not to think of possible harm until we actually commit a crime. The hard work we put into our test-suites pays back allowing us to do this harm safely so that it is OK to pay attention only to those things, which are important at the moment, ignoring most of the context.
Don't get me wrong, I am far from stating here that having tests you should not think of potential errors that you don’t catch and only hack more and more code because tests protect you. Continuing the analogy with planning, even if you have a schedule for a week you have to step back from time to time and see how it fits into the greater picture and how good are you at drawing it. My suggestion about concentration is not based on the presumption of the ability to foresee everything either – even with tests we give birth to dozens of bugs. Nevertheless, when choosing the path of test-driven development you adopt the stance of not worrying about the mistakes that your tests don’t catch until you find yourself in the green zone. Once there, you are free to pick the next goal: check if your idea about some bug is correct or start a new component – in both cases this basically means picking a name and location for a new test. At the same time, while the lights are red you should be kind of hypnotized and focused solely on the actual portion of work required to satisfy them. Fortunately, there is some strange power to everything red – even bulls can’t resist the temptation to get rid of it.
As for me, I have come to believe that what makes me test-drive programs is not the desire to be confident in their correctness – I can never be 100% sure – or the plain idea that I will spot a bug or two long before launching the program for the first time. Instead, I must be simply following the most comfortable road, because tests allow me to concentrate on my goals and enter the praised state of ‘flow’ easily. Furthermore, if I leave one red for a night, I will be able to get back to work with minimal effort next morning.
As a bonus here is a number of worthy articles devoted to different aspects of testing, which I spotted in my feed this week:
And as usual, I will appreciate any feedback: a piece of advice, an angry comment or anything else!