TDD often uses unit tests to drive behavior into the system. However, sometimes acceptance tests are used to do this. When these are automated, this can give us clues as to how to make our work in TDD more reusable.
Part of the TDD process consists of writing failing tests before the code that will eventually make them pass. Test-first alone is not TDD per se, but it is a part of it.
When tests are written before production code, this has several beneficial effects. This comes from the fact that these tests have the same orientation toward the code that client code will have in the future. Tests are, essentially, the first clients of any behaviors they drive into the system. Continue reading “TDD: Tests are Client Number 1”
In TDD, tests take actions such as Setup, Trigger, and Verify. Each of these pieces must successfully execute in order for the specification to be verified as accurate to the current behavior of the system.
If there is an external dependency, the test can become vulnerable to a failure of that entity. Continue reading “TDD and Guard Assertions”
Unit testing frameworks, which are the most common tools used by developers to conduct TDD, come with pre-made assertions that can be used to verify the behaviors being specified. Typically, these include assertions such as:
“areEqual()” (value comparison) “areSame()” (entity comparison) “isNotNull()” “contains()”
Developers should not limit themselves to these pre-made assertions. Continue reading “TDD and Naming Part 3: Customized Assertions”
Tests often establish example values used to compare the behavior of the system with the actual behavior indicated in the requirements. For example, if we had a system behavior that converted a temperature expressed in Fahrenheit to one expressed in Celsius, then the test that specified this might have an assertion along these lines:
However the use of these values directly in the assertion sidesteps an opportunity to express the meaning of those values in the specification. Continue reading “TDD and Naming: Part 2”
TDD is not really a testing activity so much as it is about the creation of an executable specification. Because of this we value different things than testers might. Naming of tests, variables, and the use of well-named customized assertions are examples.
Test names are sometimes provided by the tools we use. Continue reading “TDD and Naming: Part 1”
I’ve written a chapter in my book on The Relationship Between ATDD and Design Patterns. Essentially, ATDD provides us with quality acceptance criteria in the form of test specifications. We can use these to design our code from a behavior point of view instead of from an implementation point of view.
Doing this makes for more testable code, a quality highly correlated with other code qualities we want – strong cohesion, loose coupling and no redundancy. Design patters provide us with a method for combining these high quality objects together through the Gang of Four’s mantra’s of designing to behavior, using variation and encapsulating variation – in this case variation of type.
In the Agile world where requirements evolve, ATDD and Design Patterns Thinking work together to enable emerging designs from emerging requirements.
TDD, when conducted as a specifying activity, is an aspect of Behavior-Driven Development (BDD). Behavior is what we specify and is what we “drive” into the system using tests. Therefore, when structuring the tests in TDD we can be guided by the language of BDD: Given, When, Then.
Developers often remark that the tests may contain the same algorithms that the production code does. This feels like redundancy and makes them wonder if TDD is promoting bad practices.
Example: A system that converts Fahrenheit to Celsius. The code would contain something like this: Continue reading “TDD Replicating Algorithms”