Acceptance Test-Driven Development vs Classic TDD

Daniele Scillia (Dan The Dev)
Dan the Dev
Published in
3 min readMay 21, 2021
Photo by Alex Kulikov on Unsplash

Technical excellence is important, but it’s not enough.

Acceptance Test-Driven Development is a methodology that takes the Classic TDD and combines it with the concept of Acceptance Test.

The idea of the Acceptance Test comes from the world of engineering: they are a test to determine whether the requirements of a given specification or a given contract are met. They are therefore the formalization of acceptance criteria. Criteria define what must be done, tests define how.

In Acceptance Tests, we always recognize three sections, as in classic TDD, but they are different: instead of ARRANGE, ACT, and ASSERT we have GIVEN, WHEN, and THEN.

Acceptance testing is a type of testing that focuses on business requirements, can be not too fast, and tests the complete flow, excluding external systems.

In applying ATDD, we find the loop concept again but doubled: double loop is a key concept. It means that we have to apply the concept of the TDD loop at two levels: first to the Acceptance Test level, then to each Unit Test that drives us to the implementation of the code useful to pass the starting Acceptance Test.

For example, for an email service, we might write an Acceptance Test where a user manages to send an email correctly. To pass this test, we might write a test to build the email with all its components, a test for the SMTP client, and so on, applying the RED-GREEN-REFACTOR loop to each before moving on to the next.

This way we’ll have the first cycle, the external one, based on Acceptance Test that verifies therefore a more extended behavior; within that behavior, we’ll develop the components that serve the purpose with the second cycle, more internal and with Unit Tests, repeated for each component we need to build.

Starting from the outside brings several advantages:

  • it’s an approach that fits naturally with the business viewpoint
  • it goes from high-level responsibilities to low-level details
  • it goes from the main objective to the steps to reach it
  • it goes from strategic to tactical

The main benefit, finally, is to focus first on the most important thing: making the public API intuitive.

The differences with the classic TDD are in the way it leads you to solve your problem: with ATDD the design decisions happen in the RED phase, while we write the test; starting from the outside, will be easier to identify the responsibilities and consequently the collaborators we need and at the time we write the test those collaborators don’t exist yet; we will have to describe them with an interface and then in the tests create the relative Double.

In fact, at that moment we don’t need to implement them, but only to understand how we need to communicate with them. Writing the mock in fact is a crucial moment, in which we take design decisions about communication towards the collaborator. An obvious difference between ATDD and Classic TDD is in the assertions: if in TDD we typically make assertions on a state, with ATDD we make assertions on messages and their invocations through mock, favoring the concept of “Tell, don’t ask”.

The final question, then, is: what should I use, TDD or ATDD?
The answer is obvious: it depends!

TDD is really effective when you don’t know the problem domain and/or the problem itself well: in this situation exploration is needed and TDD helps you with that.

ATDD, on the other hand, requires more domain mastery and especially design knowledge, because you won’t get the feedback loop on it. However, if you are familiar with the problem, it makes it easier for you to think from a business perspective and is much more efficient.

--

--

Daniele Scillia (Dan The Dev)
Dan the Dev

Software Engineer @TourRadar - Passionate Dev, XP Advocate, passionate and practitioner of Agile Practices to reach Technical Excellence