OLX

You should push for BDD! Here is our journey

2024-9-24

Bernardo Vitória

Photo by Growtika on Unsplash

In the dynamic landscape of software development, achieving clarity is paramount. Enter Behavior-Driven Development, or BDD — a navigational beacon guiding developers, testers, and business stakeholders toward a unified understanding. Unlike traditional approaches that prioritize code, BDD focuses on defining behavior, laying the foundation for mutual comprehension of a software’s purpose right from the inception.

BDD embodies simplicity, articulating the anticipated behavior of software in clear terms. This collaborative methodology ensures that every team member comprehends the project's objectives irrespective of their technical expertise. By honing in on behaviors, BDD steers development with a sharp focus on user needs and overarching business goals.

Through the lens of BDD, teams embark on a journey of crafting not just software but a shared vision. The result? Products that don’t merely function but deliver tangible value. Join us as we delve into the world of BDD, exploring how this approach can streamline your development process and pave the way for outcomes that transcend expectations.

Here’s a simple example of a BDD scenario of a user who selects a product:

Scenario: Successful Login
Given the user is on the login page
When the user enters valid credentials
And clicks the login button
Then the user should be redirected to the dashboard
And the user should see a welcome message

Benefits

In the fast-paced world of software development, where agility and clarity are essential to enable teams to respond swiftly to changes while maintaining a clear focus on what needs to be built, Behavior-Driven Development (BDD) emerges as a guiding light, offering numerous benefits that transcend traditional approaches. Let’s delve into the advantages of adopting BDD practices in your development workflow.

Enhanced Collaboration and Communication

BDD promotes collaboration among developers, testers, and business stakeholders by providing a common language to discuss system behavior. By writing scenarios in a structured, user-centric format, BDD encourages dialogue and ensures that everyone involved in the project clearly understands the desired outcomes.

Given: Sets up the initial context or preconditions.
When: Specifies the action or event that triggers the behavior.
Then: Defines the expected outcome or result of the action.

Clear and Measurable Requirements

One of the core principles of BDD is defining behavior before implementation. This approach helps teams articulate precise requirements through executable scenarios, ensuring the software meets the intended business goals. With BDD, requirements become more tangible and easier to validate, reducing the risk of misunderstandings or misinterpretations.

Focus on User Needs

BDD places a strong emphasis on understanding and addressing user needs. By defining behavior from the user’s perspective, teams can prioritize features that deliver maximum value and improve the overall user experience. This user-centric approach fosters empathy and helps teams build products that resonate with their target audience.

Here’s an example; notice that the scenario is written in the third person singular.

Feature: Add Item to Shopping Cart

Given the user is on the product page
And the product is available in stock
When the user clicks the "Add to Cart" button
Then the item should be added to the cart
And the cart count should increase by 1
And the user should see a confirmation message

Early Detection of Issues

BDD encourages writing scenarios upfront, even before writing code. This proactive approach allows teams to identify potential issues and clarify ambiguities early in the development process, minimizing the risk of expensive revisions.

By incorporating testing into the requirements phase, BDD ensures that software quality is built in. This methodology extends the principles of Test-Driven Development (TDD), where developers first write tests that define the desired functionality before writing the actual code. While TDD is focused on the technical perspective and the validation of code correctness, BDD takes a step further by emphasizing behavior and the user experience. It bridges the gap between the technical language of developers and the domain language of stakeholders, ensuring that all parties clearly understand the project’s objectives. Thus, BDD not only incorporates the best practices of TDD but also enhances them by fostering better communication and collaboration among developers, testers, and non-technical stakeholders.

Automated Testing and Documentation

BDD scenarios serve as living documentation for the software’s behavior. These scenarios can be automated and integrated into the development pipeline, providing immediate feedback on the system’s functionality. Automated tests help catch regressions and ensure that the software remains stable and reliable, even as it evolves over time.

pipeline step

Improved Software Quality and Maintainability

By focusing on behavior rather than implementation details, BDD encourages writing more modular, maintainable code. The clear separation of concerns and emphasis on reusable components make it easier to refactor code and adapt to changing requirements. As a result, BDD can lead to higher-quality software that is easier to extend and maintain in the long run.

In summary, Behavior-Driven Development offers a wealth of benefits for development teams, ranging from improved collaboration and communication to enhanced software quality and maintainability. By embracing BDD practices, teams can build better products that meet the needs of users and stakeholders alike.

Visual Regression Testing (VRT)

Visual Regression Testing is a technique used to automatically detect visual differences between successive versions of a web application or user interface (UI). Incorporated into BDD, VRT shifts focus from traditional functional testing of features to the visual elements like layout, styling, and design.. It offers several key benefits for software development teams. By automatically detecting visual discrepancies between different versions of a web application, VRT ensures the preservation of design integrity, early detection of UI bugs, prevention of regression issues, improved user experience, and significant time and cost savings. By incorporating VRT into their testing strategy, teams can enhance the reliability and quality of their software products while streamlining the development process.

Here’s an example of a VRT:

Background:
Given the user type is PRIVATE

Scenario Outline: user should see packages for a pending ad
Given the advert has pending ad status
When pending ad consumers route is visited
Then packages is displayed correctly (VRT STEP)

Key Disadvantages of BDD

While Behavior-Driven Development (BDD) offers many benefits, such as improved communication and clear requirements, it also comes with some key disadvantages.

  • Initial Learning Curve: Teams unfamiliar with BDD must learn new concepts and tools, which can be time-consuming and challenging, particularly for those new to automated testing.
  • Increased Upfront Effort: Writing detailed BDD scenarios and maintaining them as requirements and code changes require significant effort.
  • Dependency on Collaboration: BDD relies heavily on collaboration between developers, testers, and business stakeholders. Lack of engagement from any group can hinder the process, and getting non-technical stakeholders involved in writing and reviewing scenarios can be difficult.
  • Miscommunication Risks: Natural language scenarios can be ambiguous, leading to misunderstandings if not written clearly.

Despite these challenges, BDD continues to evolve and influence software development. As the industry moves forward, new tools and methods are being developed to tackle these issues and make BDD even more effective. In the next section, we’ll dive into the state of the art in BDD, looking at the latest advancements and best practices that are helping teams adopt and succeed with this approach in today’s development environments.

State of the art

Behavior-driven Development

Behavior-Driven Development (BDD) is all about testing a system from the user’s perspective. Instead of writing complex test scripts, BDD encourages creating simple, human-readable stories that describe how the system should behave. These stories, or scenarios, help ensure that the implementation matches what users expect.

BDD is like a team sport, where everyone — developers, testers, and even non-tech folks — gets together to define these scenarios. By using a common language that everyone understands, BDD helps teams communicate better and avoid misunderstandings.

One cool thing about BDD is that these scenarios aren’t just for testing — they’re also living documentation. They serve as a clear picture of how the system should work, helping teams stay on the same page as the project progresses.

Overall, BDD fosters collaboration and clarity within teams, resulting in software that’s not just bug-free but also truly meets users’ needs.

Testing Trophy

A very illustrative concept that covers the importance of seamlessly integrating tests into the development workflow is the Testing Trophy, introduced by Kent Dodds in his blog post. Here’s the link

Here are the four types of tests commonly used in JavaScript applications within the context of the Testing Trophy approach:

  • Static Tests are crucial for analyzing code without executing it. In BDD, these tests help maintain clarity and consistency in the behavior specifications by ensuring that the code adheres to best practices and conventions. Static code analysis tools identify syntax errors, code style violations, and potential logic flaws, enhancing the overall quality and readability of the code.
  • Unit Tests focus on verifying the functionality of individual units or components. In the context of BDD, they ensure that each component behaves as expected according to the behavior described in BDD scenarios. These tests examine small, independent parts of the system, such as functions or methods, in isolation from the rest of the application. Automated and frequently executed during development, unit tests provide quick feedback on whether specific behaviors are correctly implemented.
  • Integration Tests come into play to validate the interactions and interfaces between integrated components. They are essential in BDD for confirming that different parts of the system work together as intended by the behavior scenarios. These tests assess communication, data flow, and interface compatibility between components, ensuring that the integrated system functions smoothly and that complex behaviors involving multiple components are correctly implemented.
  • End-to-End Tests simulate real user scenarios and interactions, validating the entire application workflow from start to finish. In BDD, these tests ensure that the software meets user expectations and behaves correctly in production-like environments. By including user interfaces, backend services, and external dependencies, end-to-end tests provide a comprehensive check of the application’s behavior, ensuring that all the specified BDD scenarios are fulfilled in a realistic context.

Their distribution:

Testing trophy by Kent C. Dodds
Integration tests strike a great balance between confidence and speed/expense.

Tools

  • Playwright: Playwright is another popular front-end testing framework that provides a high-level API for automating interactions with web applications across different browsers. It offers features like cross-browser testing, headless mode, and built-in support for multiple programming languages. Further reading link 1 and link 2
  • CucumberJS: CucumberJS is a test runner for automated tests written in the Gherkin language, which uses natural language syntax to describe software behavior. It promotes collaboration between stakeholders by enabling them to write and understand test scenarios in a human-readable format. Further reading link 1 and link 2.
  • Testing Library: The Testing Library is a collection of simple and comprehensive testing utilities designed to encourage good testing practices. It provides developers with tools for testing React components, DOM elements, and other UI elements in a way that closely resembles how users interact with the application.

Testing Library

The Testing Library is a popular choice in the industry for testing UI components, known for its emphasis on best practices and accessibility. It encourages developers to focus on testing how users interact with the application, rather than getting bogged down in implementation details.

One of its key principles is to steer clear of testing internal component workings, promoting tests that mimic user behavior instead. This approach leads to more resilient tests that adapt well to changes in component internals. Additionally, the Testing Library provides handy utilities for writing tests that closely resemble real user interactions. This not only improves test effectiveness but also boosts component accessibility for all users.

BDDs at OLX

We were constantly identifying several opportunities for improvement in our code base regarding performance, scalability, developer experience, and user experience. However, it was too risky to make significant refactors or implement large features because we lacked confidence in our current tests.

Our previous tests, based on Jest, were mostly coupled with implementation details, making them hard to maintain.

To address these issues, we decided to adopt BDD integration tests using Playwright and CucumberJS. Although we already had Cypress, we chose Playwright and CucumberJS for their better parallelization, improved performance debugging experience, and superior developer experience.

We decided to adopt BDD on June 26, 2023. After a year, in a single market, we have implemented over 1697 scenarios, of which 54 were identified as critical flows. Identifying critical flows and tackling them first is crucial. This approach helps to focus on the most important parts of your platform, ensuring that the most critical functionalities are robust and reliable. Once the critical flows are addressed, attention can be shifted to high-priority flows. This prioritization not only increases our confidence in what we are developing but also makes it much easier to implement features and refactors. We now develop BDDs as part of the feature, ensuring continuous improvement and alignment with our development goals.

Conclusion

As we wrap up our journey through Behavior-Driven Development (BDD) and its tools, we encourage you to bring these insights back to your workspace. Whether you’re aiming to improve collaboration, refine your development process, or elevate software quality, BDD provides a solid foundation.

Should you have any questions or need further guidance on integrating BDD into your projects, feel free to reach out. Additionally, if you’re passionate about building high-quality software and are looking for new challenges, we invite you to explore our job openings. Join us in shaping the future of software development.

TL;DR

Behavior-Driven Development (BDD) shifts the focus to defining behavior, fostering mutual comprehension of a software’s purpose from inception. BDD promotes collaboration and clarity within teams, while the Testing Trophy underscores integrating testing into the development workflow. Tools like Cypress, Playwright in CucumberJS, and the Testing Library facilitate user-centric testing and better parallelization. Leveraging Playwright in CucumberJS offers advantages like enhanced debugging and native support for Testing Library queries. Visual Regression Tests complement the BDD test suite, ensuring layout and design changes are implemented correctly, ultimately improving software reliability and quality.


You should push for BDD! Here is our journey was originally published in OLX Engineering on Medium, where people are continuing the conversation by highlighting and responding to this story.