Going in-depth: TDD, BDD, and ATDD approaches
Test-driven development is an iterative software development process that involves design, testing, and coding. TDD emphasizes a disciplined test-first approach, where a test that describes the intended functionality of the code is created before the code itself is written. The test is run before the code is written to confirm that the test fails. Once the code is written, the test is run again to ensure it passes.
Test-Driven Development is the foundation for other methodologies such as BDD, and ATDD. With each iteration, a small change is made to the production code, providing an opportunity for the developer to improve the design. This way, a robust and well-tested design arises. Some TDD practices include having many unit tests at the lower levels, having short iterative cycles, getting immediate and frequent feedback, and having effective use of tooling, source control, continuous integration, and guided application of programming principles and design patterns.
Unit tests are essential here, and developers write them to check the expected behavior of the production code. The tests are automated and should be easy for developers to implement and maintain. Unit tests should have the characteristics of being deterministic, atomic, isolated, and fast.
The iterative process is the foundation of Test-Driven Development. Each iteration involves making a small, focused, and carefully considered change to the program. The iterative cycle follows the red-green-refactor convention, where a failing test is written, code is added to satisfy the expectation described by the test, and then the code is refactored to improve the design and structure without changing the functionality.
- Red: Write a failing test upfront and run it to ensure that it fails
- Green: Add code that satisfies the test expectations and run to ensure that it is passing
- Refactor: Improve the structure of the code and the test without touching the functionality
The approach known as Behavior-Driven Development is affected by two practices: Test-Driven Development and Domain-Driven Design (DDD). It adopts several fundamental principles from both methodologies, including collaboration, design, ubiquitous language, automated testing, and rapid feedback loops. While Test-Driven Development primarily employs unit tests to verify implementation details, BDD utilizes executable scenarios to confirm desired behaviors and outcomes.
The typical workflow for BDD involves creating user stories, translating these stories into scenarios, implementing the desired behaviors, and testing the scenarios to verify them. The BDD approach extracts one or more scenarios from each user story, with each scenario representing a specific behavior. To ensure clarity across all team members, scenarios are written using natural language, particularly English.
Behavior-Driven Development scenarios usually have three main sections, which are “Given,” “When,” and “Then.” These sections describe the state before the behavior is triggered, the actions that trigger the behavior, and the expected results of the behavior. To extract scenarios from user stories, one must identify acceptance criteria, functional use cases, and examples, and write scenarios for each of them. Also, ensure that scenarios do not affect each other’s state, and use the third person when describing the steps. When writing scenarios, focus on specific behaviors that the system supports, use semantic actions instead of specific technical actions unless needed(try avoiding technicalities when writing the behavior), and describe specific expectations in the “Then” section.
Acceptance test-driven development (ATDD) is a process that enables coordination in software projects by ensuring that delivery is based on the customer’s requirements. Acceptance tests specify the desired behavior and functionality of a system, while user stories represent a piece of functionality that is valuable to the customer.
Once a task is completed, developers move on to the next task until the user story is finished, which is indicated by successfully executed acceptance tests. Both BDD and ATDD are customer-focused, while Test-Driven Development is developer-focused. ATDD separates the test intention from the test implementation. This separation enables business-facing and non-technical team members, such as product owners and analysts, to describe acceptance tests that can drive the development. The stakeholders collaborate to reach a shared understanding of the problem to be solved and to explore concrete, testable examples of the required behavior. The emphasis is on valuable examples rather than tests, which encourages team members to be engaged in the discovery process.