If you here reading this then you must be aware of the transition of software development from waterfall to agile over the past decade. Agile needs continuous change and has brought testing to the forefront to ensure quality is not an after-thought. The debate of TDD vs BDD has its roots in shift towards customer-centric software design.
Ask any developer and they must be aware of test-driven development (TDD) technique. However, there is a chance they may not know as much about behavior-driven development (BDD) approach. Both the techniques come with its own upsides and downsides.
We are going to deep-dive into both the approaches and do a comparative study of their pros, cons and differences. Let’s get started with analysis of TDD vs BDD!
What is Test-driven development (TDD)?
It is a software development process that repeats short development cycles. Simply put, codes are written for a specific functionality and tests are repeated unless its passed. When following this method, developers are confident that the code does the job accurately. This process improves the code quality and eliminates any technical debt. The entire life-cycle of a TDD is often referred to as the red-green refractor cycle.
Refer to the image below and you would clearly see the cycle. A developer can start with a failing test and modify the code where necessary to fix the error and make the code green. The refractor stage – changing or adding parts of the existing code, without affecting the behavior of the entire code – too plays a vital role in the TDD method.
Kent Beck, a unit testing pioneer used the TDD approach. What we also think worth explaining is the bottom-up and top-down TDD approach.
Also known as the inside-out TDD, this approach builds functions iteratively – building one entity at a time. It targets to pick a function and solidify its behavior before moving on to the next one. One could say that it builds everything in layers. It is most likely to start by scripting the unit-level code, followed by its implementation. Further, it would go on to write high-level test that solidify the functionalities of the lower-level tests and so on.
The layered approach eventually gets to a stage where the highest level test remains just an acceptance test. The bottom-up TDD approach is known to be highly developer-centric and functions around making their lives easier.
Focus is on one functional entity at a time
Delays integration stage
Functional entities are easy to identify
Amount of behavior an entity needs to expose is unclear
High-level vision not required to start
High risk of entities not interacting correctly with each other thus requiring refactors
Business logic possibly spread across multiple entities making it unclear and difficult to test
Also known as outside-in TDD method, this takes the opposite route to the bottom-up approach by starting to build a system and adding details to the process through it. It requires a series of steps to be repeated, while being tweaked and improved with each cycle. The entire idea behind this being breaking each step into smaller entities, which starts with writing a acceptance-level test and proceed with minimal implementation.
This test needs to be done incrementally and hence before building any new entity, it requires tests at appropriate levels. This approach is more business or customer-centric and is relatively more complex as it relies heavily on seamless communication between parties. Nonetheless, the pros to this approach outweighs the cons. If done successfully, the approach results in a clearly-defined system, flows and a predictable workflow and outcome.
Focus is on one user requested scenario at a time
Critical to get the Assertion-Test right thus requiring collaborative discussion between business/user/customer and team
Flow is easy to identify
Relies on Stubbing, Mocking and/or Test Doubles
Focus is on integration rather than implementation details
Slower start as the flow is identified through multiple iterations
Amount of behavior an entity needs to expose is clear
More limited parallelization opportunities until a skeleton system starts to emerge
User Requirements, System Design and Implementation details are all clearly reflected in the test suite
What is Behavior-driven development (BDD)?
We might have successfully explained the bottom-up TDD approach, which is developer-centric and produces better code-base and test suite. On the contrary, the top-down TDD approach is more customer-centric and produces overall better results. Dan North, with his experiences with both the TDD approaches proposed bringing together the best aspects of both and introduced the BDD approach. The new development approach eliminated all the shortcomings of the two and helped with more valuable testing behavior than functional testing.
In a tweet Dan North explained BDD as, “Using examples at multiple levels to create shared understanding and surface uncertainty to deliver software that matters.”
This technique requires different parties to collaborate through the project delivery timeline. It needs a developer, test engineer, product manager and other stakeholders to define and formalize a system’s behavior to a common, domain-specific language that is understood by all parties. It then goes on to use this definition to write an executable test.
BDD thrives on a successful direct collaboration between the team and the customer. It becomes vital that the system’s behavior is defined correctly to run accurate behavioral tests. One common practice is to assume the behavior of the system. This usually occurs when a test is run keeping in mind the implementation detail, making it a functional test and not a behavioral test. Bear in mind that the BDD-based approach must result in a full test coverage where the system’s behavior is vividly described to all parties by using a common language.
TDD vs BDD: Key Differences
If we were to compare TDD vs BDD directly, we would say the main differences being:
Delivery of a functional feature
Delivering on expected system behavior
Bottom-up or Top-down (Acceptance-Test-Driven Development)
A test case
A user story/scenario
All Team Members including Client
A functioning system that meets our test criteria
A system that behaves as expected and a test suite that describes the system’s behavior in human common-language
Over-engineering, low test coverage, and low-value tests
Deviation from intended system behavior
Change in implementation can result in changes to test suite
Test suite-only needs to change if the system behavior is required to change
Difficulty of Implementation
Relatively simple for Bottom-up, more difficult for Top-down
The bigger learning curve for all parties involved
TDD vs BDD - Which Route to Take?
Understanding which approach would work better for a task at hand is the right approach. More often than not, the solution would lie in both the approaches. In larger projects there might arise a need to adopt both the development techniques at different stages of the project life-cycle.
TDD might be a more developer-friendly choice, benefitting the technical team, whereas BDD will focus on driving better communication between all parties involved and deliver a customer-friendly result.
There is no one-stop solution to everything, the knowledge and understanding of both the development techniques will allow teams to make better decisions so as to which method is best for a given project.