In the last couple of years, there's been a lot of debate in the community on the philosophy behind TDD and where to put the emphasis - even to the point of debating whether the acronym stands for Test-Driven Development or Test-Driven Design.

Other people don't like the emphasis on tests, since that makes TDD sound like a Testing discipline, and not a Development discipline. Instead, they prefer terms like Example-Driven Design/Development (EDD) or even Design by Example (DbE).

This view seems to me to be particularly prevalent in Microsoft, where there's a rather sharp distinction between developers and testers (job titles to the contrary) - I guess that's one of the reasons why xUnit.net (a project initiated by Microsoft employees) uses the attribute Fact instead of Test or TestMethod.

For people used to SCRUM or other agile methodologies, this distinction is more blurred, and they also seem to accept the T in TDD more willingly.

However, the adherents of EDD claim that the mere presence of the word test make some developers block any further input and stop listening. They may be right in that.

They also claim that the tests in TDD/EDD are nothing more than accidental artifacts of the development process, and hence argue that we shouldn't call them tests at all. However, if that's true, this little story related by Ayende must be an example of EDD in its purest form :)

To me, the tests are also important. Since 2003 I've been practicing TDD, and while I love how it helps me arrive at better design, I also savor the safety net that my suite of tests gives me. The tests that I write during TDD define the behavior of the software. In many cases, I'd even claim that such a regression test suite is more valuable than a Quality Assurance (QA) regression test suite - after all, a QA suite may catch some edge cases, but they don't focus on the intended behavior of the system, but often more on how to break it - but I digress…

My recent posts on Executable Specification and Constrained Non-Determinism help explain my current stance in this debate: In my opinion, EDD fails to establish a relationship by not providing Derived Values. After all, what does a test like the following specify?

[TestMethod]
public void InvertWillReverseText_Naïve()
{
    // Fixture setup
    MyClass sut = new MyClass();
    // Exercise system
    string result = sut.Invert("ploeh");
    // Verify outcome
    Assert.AreEqual<string>("heolp", result, "Invert");
    // Teardown
}

How would you implement the Invert method? Here's one possible implementation:

return "heolp";

Obviously, you could now write a new test that gives a second example of input and outcome and force me to write a more sophisticated algorithm. However, with only two examples, I might still be tempted to write a switch statement with some hard-coded return values until you've written so many ‘examples' that you've coerced me into writing the more general (and correct) algorithm.

Such an approach I find inefficient.

Instead, by using Constrained Non-Determinism to force myself to define Derived Values, each test fully specifies the desired behavior. It doesn't provide examples. It provides the specification, and instead of having to write several similar examples to coerce a general algorithm to emerge, I can usually nail it in a single test.

This approach could be styled Specification-Driven Development, and that's how I've been writing code for the last year or so.


Comments

Just a comment... Remember the pattern in TDD: Red, Green, Refactor. You're not supposed to write a second test in order to force you to remove the hardcoded return "heolp"; implementation. You're supposed to remove duplication during the refactoring stage. The constant "heolp" is duplicated in the test and in the implementation code, and according to Kent Beck this is your main focus during refactoring; to eliminate duplication.
2009-03-28 12:28 UTC
Hi Torbjørn

Thank you for your comment.

First of all: I'm a big believer in the Red/Green/Refactor cycle, so we're totally on the same page there!

As the test in the example stands, the constant "heolp" is most certainly duplicated across test and implementation code, until the point when I decide to implement the Invert method correctly. So far I can only agree, but partially because my example is so simple: Once again I fall into the trap that my example is too simple, but had I made it more complex, I'd have lost my reader(s) long ago.

One or few 'examples' would be enough to clue anyone on to the fact that the intended algorithm of the Invert method is to invert the input. It's fairly obvious.

Imagine, instead, that we're testing a hypothetical CalculateRocketTrajectory method. Yes, we're attempting to implement a Domain Model over rocket science! Unless you are a rocket scientist, it's likely that it's going to take a pretty big amount of 'examples' before you can figure out what is the underlying algorithm. It would be much more efficient if each test could simply specify the relationship between input and output.

Yes, that would lead to a bit of duplication across the test code and the implementation code, but I prefer that to the alternative. In my experience, most software development isn't about algorithm development anyway; it's about API design, Domain Modeling, handling corner cases, moving and transforming data, etc.

This is not to say that I am right and you are wrong. Here, I'm mainly trying to describe what motivates me to work in a certain way, so please feel free to keep the discussion going!
2009-03-28 13:55 UTC
I expect you have much more actual experience with TDD (or EDD or DbE or BDD) then myself. Since I just read Beck's TDD book and had it fresh in mind, I just wanted to give my comment, for your readers mostly, since I felt that part of the pattern wasn't represented in your post.

Keep up the nice posts.., enjoying your blog!
2009-03-28 18:01 UTC
Hi Torbjørn

Thanks again. You point was valid and well taken.

One of the reasons I find EDD ineffecient stems from my experience with The XP Game, which is enjoyable, but a bit too much on the back-and-forth side for my tastes.

YMMV, so I'm not trying to dictate what anyone should do - I'm just trying to demonstrate that there are more than one way to do TDD.
2009-03-28 19:54 UTC


Wish to comment?

You can add a comment to this post by sending me a pull request. Alternatively, you can discuss this post on Twitter or Google Plus, or somewhere else with a permalink. Ping me with the link, and I may add it as a comment.

Published

Tuesday, 10 March 2009 21:04:38 UTC

Tags



"Our team wholeheartedly endorses Mark. His expert service provides tremendous value."
Hire me!