Driving Better Code with TDD

Sabyna Maharani
6 min readApr 10, 2023

--

Hey, you there! Are you tired of spending hours, no, days debugging your code? Well, have no fear, Test-Driven Development (TDD) is here!

Understanding Test-Driven Development (TDD)

Photo by quickmeme

Test-Driven Development (TDD) is an essential methodology in modern software development, where tests are written before the actual code. This approach helps ensure code quality, maintainability, and robustness. In short, it is totally a game-changer!

Yes! I know it sounds weird to write tests before the code, but hear me out. TDD is like having a personal assistant who double-checks everything you do. You tell it what you want to achieve, and it will make sure you get there with fewer headaches and less time wasted.

By writing tests first, you can prevent bugs from creeping in and ensure your code is reliable. And let’s face it, who doesn’t want to be reliable, am I right? Plus, when you’re in the zone, writing code like a rockstar 🤘, it’s easy to lose track of all the moving parts.

But with TDD, you have a suite of tests to make sure your code still works as expected. It’s like having a bouncer at the club to make sure only the right code gets in. So next time you’re writing code, give TDD a try. It may sound weird, but trust me, it’s worth it.

TDD Process

This process involves three main steps that can be known as Red, Green, Refactor. Those are the only three words you need to know.

  1. Red: Write a failing test before you even start writing code.
  2. Green: Write just enough code to make the test pass
  3. Refactor: Refactor the code for readability, maintainability, and performance. In shorts, make the code better.

By following these steps iteratively, developers can ensure that their code meets requirements, is less prone to bugs, and is easier to maintain.

TDD Diagram

Choosing Test Library for Project

Integrating Next.js with React Testing Library was straightforward and beneficial.

Benefits of Implementing TDD in Our Project

Our team found that implementing TDD using React Testing Library in our Next.js project had numerous benefits, including:

  1. Improved Code Quality: Writing tests before developing the components allowed us to identify potential issues early and ensure that our code was robust and met requirements.
  2. Easier Maintenance: With a comprehensive test suite, our team could refactor and add new features with confidence, knowing that our tests would catch any regressions.
  3. Enhanced Collaboration: Our shared test suite provided a clear understanding of the project requirements and acted as a “living documentation” for our team, improving communication and collaboration.

Implementing TDD with React Testing Library

React Testing Library is a popular testing library designed for testing React components in a user-centric way. It emphasizes accessibility and encourages developers to write tests that closely resemble how users interact with the application. Our team found it to be the perfect tool for implementing TDD in our @/aspiring project.

1. Writing Tests

Just like explain before, to start, we wrote tests for each component, focusing on user interactions and expected outcomes. This helped us identify edge cases and ensure that our components met the project requirements.

Then how to make sure that the test we write is already well made? Should we create a test to test the test file we made? 🤯. Don’t worry, we don’t need to do that😆. We can just follow the F.I.R.S.T principle which is principles that can help to write well-crafted unit tests and will make testing easier.

The acronym F.I.R.S.T stands for:

  1. Fast — Tests should run quickly so that they can be executed frequently, ideally in a matter of seconds.
  2. Independent — Tests should not depend on each other, so that they can be executed in any order, and a failure in one test does not affect the results of other tests.
  3. Repeatable — Tests should produce consistent results every time they are executed, so that any failure can be easily reproduced and debugged.
  4. Self-validating — Tests should have a clear pass or fail criteria, so that it is easy to determine whether a test has passed or not.
  5. Timely — Tests should be written in a timely manner, ideally before the code that they are testing has been written.

Besides that principle, we must also make sure that we create all cases including positive and negative test cases.

What’s positive and negative test cases?

  1. A positive test case is designed to test the intended behavior of the software. It involves providing input data or conditions that the software is designed to handle and verifying that the output or result is correct. For example, if the software is designed to add two numbers, a positive test case would be to input two numbers and check if the output is the sum of those two numbers.
  2. A negative test case is designed to test the software’s ability to handle unexpected or invalid inputs or conditions. It involves intentionally providing input data or conditions that the software is not designed to handle and verifying that the software responds in an appropriate way, such as displaying an error message or handling the input gracefully.
    For example, a negative test case for the addition software mentioned above could be to input non-numeric characters or inputting numbers that are too large or small to be handled by the software.

Both positive and negative test cases are important for thorough testing of software. Positive test cases help ensure that the software behaves as expected, while negative test cases help uncover potential issues and ensure the software can handle unexpected situations appropriately.

example of @aspiring’s Post Modal test

For this step, my team, @/aspiring, writes the test first with a commit message test: that gives a flag this change contains code of test file only.

example of @aspiring’s test commit

2. Writing Components

After writing our tests, we moved on to developing the React components themselves. We aimed to write the minimum amount of code required to make our tests pass, ensuring that our components were built to specification.

For this step, my team, @/aspiring, writes the implementation of component with a commit message feat: that gives a flag this change has already implemented the component code and the test has to pass and succeed.

example of @aspiring’s feat commit

3. Refactoring

With our tests passing, we then focused on refactoring the code to improve readability, maintainability, and performance. React Testing Library’s user-centric approach helped us maintain confidence in our code as we refactored, knowing that our tests would catch any regressions.

For this step, my team, @/aspiring, writes the improvement of component with a commit message refactor: that gives a flag this change contains the improvement version of the component written before.

example of @aspiring’s refactor commit

Last but not least, don’t forget to make sure that the test really cover all lines and cases of the your code implementation as the best practice!

@aspiring’s PostModal test coverage

And there you have it!✨ You have learned about TDD by my story of experience during @/aspiring team’s journey. With Test Driven Development at your fingertips, you can supercharge your development process and create better software faster than ever before. TDD may take some getting used to, but once you embrace it, you’ll never look back. So get ready to wave goodbye to bugs and glitches and say hello to high-quality, rock-solid software that will make you and your users happy. Let’s revolutionize the world of software development together with Test Driven Development!

That’s all I can share in this article. See you in the following articles with more exciting themes awaiting! Happy Coding! 👩‍💻✨

--

--

No responses yet