3

Despite being very stakeholders friendly, ATDD aimed to provide a "stop" line when a feature has just been done. This avoids wasting time to add non-focused (and sometimes useless) code.

That's why some teams start by establishing a walking skeleton of the application, and directly specifying with an acceptance test the first required feature.

Let's suppose this first acceptance test (not representing a relevant first acceptance test, just being an example):

Given Michael has just been created in the application, his status should be left to non-activated.

I want to write my acceptances tests focusing on business logic directly (use-cases), not dealing with GUI for business rules.

Thus my question would be...how to write it? since I don't even already know what is a "User", what is a status etc... Indeed, shouldn't it be the role of TDD to emerge the design and therefore these components?

But if I firstly practice TDD in order to emerge them, the benefit of ATDD (as a stop line) would disappear.

I imagine that it would be more consistent to write some acceptance tests (before entering TDD cycle) when the project has well progressed, since all main components would already be designed.

To sum up, should I always write my acceptances test BEFORE my TDD cycle?

4 Answers 4

11

Acceptance tests access the application through a special purpose API.

You presented this use case:

Given Michael has just been created in the application, his status should be left to non-activated.

The API implied from this use case is something like:

CreateUser(String name);
enum UserStatus {non-activated};
UserStatus GetUserStatus(String name);

So far this has nothing to do with TDD. It's just a simple API that your acceptance tests can use to access the application.

Now, to make this acceptance test pass, you'll have to implement this API. That's when you start doing TDD. The decisions you make while test-driving the solution will help you determine the design of the application.

Note that the design of the application has nothing to do with the design of the API that's used by your acceptance tests. That API is an adapter layer between those tests and your application. That layer allows your application to assume any design you so desire.


Regarding TDD and design. It is true that design emerges from TDD. But TDD is not the sole process by which you design your application. You also think through the design in many other ways. You might draw some UML diagrams. You might use CRC cards. You might have a design session with your co-workers. Indeed, you should likely do ALL of these things.

And you should also allow designs to emerge with TDD. TDD doesn't replace previous design tools, it adds a new tool to the kit.

Some folks will likely complain that this sounds like BDUF, and doesn't sound very "Agile". The problem with that is the letter 'B'. It's entirely true that we don't want to do BIG design up front. But it's not true at all that we don't want to do some design up front. We do! A few hours, or even days of design up front is not bad. Months and months of it is.

1
  • 1
    I guess I see the trick: Trying to make acceptance tests (especially the first ones) deal with Concept (user creation, status retrieval etc..) rather than real objects belonging to application design. I well imagine that the GetUserStatus method would better fit inside the future potentially emerged User object. But this api just acts as an adapter layer as you explained (a level of indirection to User's getStatus method), allowing acceptance test to be agnostic of design application the most as it can (especially beneficial when starting a project from scratch). Thanks Uncle Bob :)
    – Mik378
    Commented Jul 26, 2013 at 15:10
6

...shouldn't it be the role of TDD to emerge the design and therefore these components?

No.

This is a common misconception about TDD. The purpose of TDD is not to "grow a design." The purpose of TDD is to insure that a program stays "well-designed." TDD will force you to create an API that's testable, and specific functional requirements will emerge from that. But it will not create your design for you. You have to do that yourself.

enter image description here

ATDD will help you design your program by providing concrete, testable customer requirements. It is an eminently practical approach: by stating the acceptance test requirements up front, the customer has told you exactly what your program must do in order to declare success.

See Also
Jim Coplien and Bob Martin Debate TDD
Return of Uncle Bob (page 3)

10
  • 2
    Sorry, but I disagree. Your description fits very well the Test-First approach but not the TDD philosophy where design emerges from Refactoring. : stefanhendriks.wordpress.com/2012/03/31/…
    – Mik378
    Commented Jul 23, 2013 at 18:43
  • 2
    "If you're not thinking through the architecture, if what you're doing instead is ignoring architecture and throwing tests together and getting them to pass, you're destroying the thing that will allow the building to stay up because it's the concentration on the structure of the system and solid design decisions that help the system maintain its structural integrity." -- Uncle Bob Martin. Commented Jul 23, 2013 at 18:46
  • 1
    Yes, but he's talking about the lack of refactoring step while applying TDD. Indeed, this would end up with a huge mess if TDD is seen as just passing from red to green.. But main of the architecture is emerged by TDD
    – Mik378
    Commented Jul 23, 2013 at 18:49
  • 2
    No, I don't think so. I'll give you the full context of the quote... Go here: s3.amazonaws.com/hanselminutes/hanselminutes_0171.pdf, and search for the word "carpet". How in the world could you expect something like MVC to emerge from red, green, refactor? Commented Jul 23, 2013 at 18:51
  • 1
    @Mik378: That's a different kind of design; it's bottom-up design. There's nothing wrong with that; it's a perfectly legitimate technique for building libraries and utilities. But you can't expect to rely on it for a complete top-down system design driven by customer requirements. Commented Jul 23, 2013 at 18:56
6

In practice, I tend to leave the design a bit rough when first starting out with an acceptance test, just introducing simplistic versions of concepts to make progress. The trick is recognise when you have enough information about the implicit design to refactor.

Actually, I think you have a bigger problem with your first test. You're starting with the first step in the sequence, not the most important/interesting feature of the system. Michael doesn't really care about the user creation process, so you could start with hard-coded users and take it from there.

1

Thus my question would be...how to write it? since I don't even already know what is a "User", what is a status etc... Indeed, shouldn't it be the role of TDD to emerge the design and therefore these components?

Not sure what you mean by "don't know what is a User", but I'd argue this kind of big business concepts don't emerge out of thin air in code as a result of the TDD process, they should be known in advance, at least in broad outline.

Approaches like Domain Driven Design recommend having preliminary collaborative modelling sessions where domain expert and developer sit together, exploring domain concepts and starting to grow a ubiquitous language.

Early sketches of the domain model resulting from these conversations should provide a basic plan to get you started with acceptance tests. Expressing ATDD tests should feel easier and more natural since you just keep on using the same ubiquitous language as before to write down big domain concepts in code.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.