Skip to content

Commit

Permalink
docs(blog): update tdd post. (#6368)
Browse files Browse the repository at this point in the history
  • Loading branch information
necatiozmen authored Sep 26, 2024
1 parent 9967b7c commit d6a6ea6
Showing 1 changed file with 173 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ image: https://refine.ams3.cdn.digitaloceanspaces.com/blog/2023-06-09-tdd-vs-bdd
hide_table_of_contents: false
---

**_This article was last updated on January 25, 2024 to add comparison table and more detailed usecases of TDD and BDD_**
**_This article was last updated on September 24, 2024 to include advanced TDD and BDD techniques, common pitfalls, and how to avoid them._**

## Introduction

Expand All @@ -21,15 +21,15 @@ In this article, you’ll learn about Test-Driven Development (TDD) and Behavior
Steps we'll cover:

- [Overview of Test-Driven Development](#overview-of-test-driven-development)
- [Pros and cons of TDD](#pros-and-cons-of-tdd)
- [Step-by-step demo example of TDD implementation](#step-by-step-demo-example-of-tdd-implementation)
- [Overview of Behavior-Driven Development](#overview-of-behavior-driven-development)
- [BDD testing](#bdd-testing)
- [Pros and cons of BDD](#pros-and-cons-of-bdd)
- [Step-by-step demo example of BDD implementation](#step-by-step-demo-example-of-bdd-implementation)
- [When to use BDD (Behavior-Driven Development)](#when-to-use-bdd-behavior-driven-development)
- [When to use TDD (Test-Driven Development)](#when-to-use-tdd-test-driven-development)
- [When to use BDD (Behavior-Driven Development):](#when-to-use-bdd-behavior-driven-development)
- [When to use TDD (Test-Driven Development):](#when-to-use-tdd-test-driven-development)
- [Common Pitfalls and How I Avoid Them in TDD](#common-pitfalls-and-how-i-avoid-them-in-tdd)
- [Common Pitfalls and How I Avoid Them in BDD](#common-pitfalls-and-how-i-avoid-them-in-bdd)
- [Comparison of TDD and BDD](#comparison-of-tdd-and-bdd)
- [Bonus: Advanced TDD and BDD Techniques](#bonus-advanced-tdd-and-bdd-techniques)

## Overview of Test-Driven Development

Expand Down Expand Up @@ -364,6 +364,75 @@ The tests will pass once you add the appropriate code to implement the scenarios
- **Regulatory compliance and documentation**: In environments where there is a need for detailed documentation of the development process for regulatory compliance, TDD can provide an audit trail of tests that correspond to specific requirements of the system.
- **Continuous integration environments**: TDD is ideal in continuous integration environments where tests are run frequently. It ensures that new code does not break existing functionality, thus facilitating continuous improvement of the code with minimal disruption.

## Common Pitfalls and How I Avoid Them in TDD

**Too Many Small Tests are Being Written**
This often gets me caught up in writing tests for every little function or method. It feels so complete, but it's really just slowing me down and making the test suite a lot more maintenance-heavy.

**How I avoid it:** I now test the whole system most of the time for its behavior rather than testing all internal details.

```javascript
// Cannot test private or tiny methods.
test('should add item to cart', () =>
const cart = new ShoppingCart();
cart.addItem({ name: 'Book', price: 10 });
expect(cart.items.length).toBe(1);
);
END
```
**No Refactoring**
I had often been tempted, once it passed, to just move on and skip cleaning up the code. But not refactoring usually begets messy, hard-to-maintain code later on.
Always take the time to refactor immediately after getting the test to pass. That's why TDD's "Red, Green, Refactor" is so important.
**Writing Code Before Tests**
This is also you can often find me writing the code first, then subsequently adding tests for; it's here I've realized that indeed buries the advantages of TDD.
Now, I write the test always first—even if it takes some extra time upfront. This way, I can catch bugs quickly and remain focused on my goal.
## Common Pitfalls and How I Avoid Them in BDD
**Too General or Too Specific Writing Scenarios**
I notice that both very vague and very highly detailed writing of scenarios leads to confusion: where they are vague, they miss important behavior; where they are too detailed, it is overwhelming.
I strive to focus my attention on the writing of scenarios that describe users' behavior in free text, striking a balance between the level of detail and clarity.
```gherkin
Scenario: User logs in successfully
Given the user is on the login page
When the user inputs correct credentials
He will then be taken to the dashboard.
```
**Not Involving Non-Technical Stakeholders**
I had written some BDD scenarios in the past when I did not collaborate enough with the product owners or stakeholders. The scenarios weren't really aligned with the business need in those cases.
I make sure to involve product owners and nontechnical stakeholders up-front because this means that scenarios reflect real business goals.
**Not Automating BDD Tests**
I have from time to time written good BDD scenarios yet didn't automate them, which led to missed tests and manual errors.
**How I avoid it:** I always use tools like Cucumber in order to automate the BDD tests—so all go smooth and consistent.
```javascript
END // Example of BDD scenario automation using Cucumber.js
const { Given, When, Then } = require('@cucumber/cucumber');

Given('the user is on the login page', function ()

// code to divert to the login page
})

When('the user enters valid credentials', function () {

//Credentials Input Code END Then('the user is redirected to the dashboard', function () // code to check the redirecting to dashboard );
END
```
## Comparison of TDD and BDD
So far, you've learned what TDD and BDD are, what they entail, and how they work. Let's look at how they differ in various aspects, as shown in the table below:
Expand All @@ -387,6 +456,103 @@ So far, you've learned what TDD and BDD are, what they entail, and how they work
<br/>
# Conclusion
## Bonus: Advanced TDD and BDD Techniques
Lately, I have been looking at some of the more advanced TDD and BDD techniques. For me, these have made the difference, mainly in controlling some complex test cases.
### Advanced TDD Techniques
**Mocking and Stubbing**
Whenever I have code that depends on something external, like a database or an API, testing gets really tricky. Mocks and stubs help me feel like I'm really insulating what I'm trying to test.
I utilize mocking frameworks in order to simulate some external dependencies so that the tests will stay fast and focused.
```javascript
const fetchData = require("./fetchData");
const axios = require("axios");

jest.mock("axios");

test("should fetch user data", async () => {
const user = { name: "John" };
axios.get.mockResolvedValue({ data: user });

const result = await fetchData();
expect(result.name).toBe("John");
});
```
In the following example, the `axios.get` method is mocked away from useEffect in order to simulate an API request for testing the behavior of `fetchData`.
**Testing Edge Cases and Exceptions**
TDD is great for ensuring that code works as expected, but it's equally important to test how it will handle unexpected or invalid inputs. I always try to write tests that cover the edge cases of exceptions.
I write tests for unexpected input values, null values, or edge cases that might not occur frequently but may cause the application to break.
```javascript
test("should return an error when there is no data", () => {
const func = () => processData(null);
expect(func).toThrow("Invalid data");
});
```
I am testing here how my function handles a null input. This should raise an error.
### Advanced BDD Techniques
**Summarizing the Case**
In my experience with BDD, scenario outlines can definitely help in reducing repeated tests for the same scenario with different values in data.
Scenario outlines allow you to write a single test structure and run it multiple times with different inputs. This will save you time and clean up the scenarios.
```gherkin
Scenario Outline: Verifying user input
Given that "<input>" are the user inputs
When the form is submitted by the user
Then the message "<message>" shall appear

Examples:
| input | message |
| John | Input is valid |
| "" | Input is required |
| 123 | Error Input |
```
In this scenario, running the scenario a few times with different inputs helps me concisely cover a number of different cases.
**Selective Testing Using Tags**
When working on big projects, running all BDD tests may take much time. In BDD, I have started using tags to run selectively only the scenarios in focus.
I label scenarios based on priority or feature so at development time I can run selected sets of tests.
```gherkin
@login
Scenario: User has logged in successfully
Given the user is on the login page
When the user enters valid credentials
Then the user is redirected to the dashboard
```
In practice, what it means is that, at any given time, working on the login functionality, I run only the tests tagged as having `@login` but not all tests.
**BDD with Continuous Integration**
BDD tests incorporated into the CI pipeline changed my professional life. It ensured that the scenarios are tested automatically after every code change.
I have configured BDD tools such as Cucumber to run as part of CI processes so that the behavior is continually validated.
```yaml
# Example CI pipeline with BDD tests
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Run BDD tests
run: npm run cucumber
```
These BDD tests can be used in automation form within the CI pipeline to catch potential behavioral issues quite early, and also ensure at all times that the code behaves as per expectation.
## Conclusion
Finally, you've reached the end of this article, where you learned about Test-Driven Development (TDD) and Behavior-Driven Development (BDD), including what they entail, their principles, their benefits and drawbacks, and how they differ. You also saw TDD and BDD in action in a demo application.

0 comments on commit d6a6ea6

Please sign in to comment.