Introducing BDD (2006)

locknitpicker1 pts0 comments

Introducing BDD | Dan North & Associates Limited<br>Introducing BDD<br>Table of Contents<br>20 Sep 2006

13 mins

I had a problem. While using and teaching agile practices like test-driven development (TDD) on projects in different environments, I kept coming across the same confusion and misunderstandings. Programmers wanted to know where to start, what to test and what not to test, how much to test in one go, what to call their tests, and how to understand why a test fails.<br>The deeper I got into TDD, the more I felt that my own journey had been less of a wax-on, wax-off process of gradual mastery than a series of blind alleys. I remember thinking &ldquo;If only someone had told me that!&rdquo; far more often than I thought &ldquo;Wow, a door has opened.&rdquo; I decided it must be possible to present TDD in a way that gets straight to the good stuff and avoids all the pitfalls.<br>My response is behaviour-driven development (BDD). It has evolved out of established agile practices and is designed to make them more accessible and effective for teams new to agile software delivery. Over time, BDD has grown to encompass the wider picture of agile analysis and automated acceptance testing.<br>Test method names should be sentences<br>My first &ldquo;Aha!&rdquo; moment occurred as I was being shown a deceptively simple utility called agiledox, written by my colleague, Chris Stevenson. It takes a JUnit test class and prints out the method names as plain sentences, so a test case that looks like this:<br>public class CustomerLookupTest extends TestCase {<br>testFindsCustomerById() {<br>...

testFailsForDuplicateCustomers() {<br>...<br>...

renders something like this:<br>CustomerLookup<br>- finds customer by id<br>- fails for duplicate customers<br>- ...

The word &ldquo;test&rdquo; is stripped from both the class name and the method names, and the camel-case method name is converted into regular text. That&rsquo;s all it does, but its effect is amazing.<br>Developers discovered it could do at least some of their documentation for them, so they started to write test methods that were real sentences. What&rsquo;s more, they found that when they wrote the method name in the language of the business domain,the generated documents made sense to business users, analysts, and testers.<br>A simple sentence template keeps test methods focused<br>Then I came across the convention of starting test method names with the word &ldquo;should.&rdquo; This sentence template—The class should do something —means you can only define a test for the current class. This keeps you focused. If you find yourself writing a test whose name doesn&rsquo;t fit this template, it suggests the behaviour may belong elsewhere.<br>For instance, I was writing a class that validates input from a screen. Most of the fields are regular client details—forename, surname, etc.—but then there is a field for date of birth and one for age. I started writing a ClientDetailsValidatorTest with methods like testShouldFailForMissingSurname and testShouldFailForMissingTitle.<br>Then I got into calculating the age and entered a world of fiddly business rules: What if the age and date of birth are both provided but don&rsquo;t agree? What if the birthday is today? How do I calculate age if I only have a date of birth? I was writing increasingly cumbersome test method names to describe this behaviour, so I considered handing it off to something else. This led me to introduce a new class I called AgeCalculator, with its own AgeCalculatorTest. All the age calculation behaviour moved into the calculator, so the validator needed only one test around the age calculation to ensure it interacted properly with the calculator.<br>If a class is doing more than one thing, I usually take it as an indication that I should introduce other classes to do some of the work. I define the new service as an interface describing what it does, and I pass this service in through the class&rsquo;s constructor:<br>public class ClientDetailsValidator {

private final AgeCalculator ageCalc;

public ClientDetailsValidator(AgeCalculator ageCalc) {<br>this.ageCalc = ageCalc;

This style of wiring objects together, known as dependency injection, is especially useful in conjunction with mocks.<br>An expressive test name is helpful when a test fails<br>After a while, I found that if I was changing code and caused a test to fail, I could look at the test method name and identify the intended behaviour of the code. Typically one of three things had happened:<br>I had introduced a bug. Bad me. Solution: Fix the bug.<br>The intended behaviour was still relevant but had moved elsewhere. Solution: Move the test and maybe change it.<br>The behaviour was no longer correct; the premise of the system had changed. Solution: Delete the test.<br>The latter is likely to happen on agile projects as your understanding evolves. Unfortunately, novice TDDers have an innate fear of deleting tests, as though it somehow reduces the quality of their code.<br>A more subtle aspect of the word should becomes...

test class method behaviour name agile

Related Articles