Test-Driven Development (TDD)

Test-Driven Development (TDD) is a software development approach where tests are written before the actual code. Developers first define the specifications or requirements of the feature as test cases and then write code to pass those tests.

Goal

The primary goal of TDD is to improve the design of features and write cleaner, more testable code. It aims to improve both the quality of the software and the productivity of developers by reducing debugging time and enhancing code clarity.

Context

There are infinite ways to write code like there are infinite ways to write a book. But not all ways are equal. We need code to be testable so that we can automate our validity checks. We need code to be maintainable so that we can continue to iterate on the code without slowing down through increasing technical debt. We need code to be reliable so that we can spend time building features instead of fixing bugs. TDD is a practice that helps us achieve these goals.

Types of TDD

FormatDescriptionBenefitsConsiderationsBest Suited For
London School (Outside-In)Starts with user interface (UI) or API interactions. Focuses on testing overall application behaviour from a user's perspective.
  • Easier debugging due to user interaction focus.
  • Well-suited for complex UIs or integrations.
  • Promotes separation of concerns (Command-Query Separation).
  • Tests can become brittle and require frequent updates.
  • Overuse of mocks can mask underlying design issues.
  • Projects with complex UIs or external integrations.
  • Teams new to TDD (easier to grasp core functionalities).
Chicago School (Inside-Out)Starts with domain logic and core functionalities. Focuses on testing the internal state and behaviour of individual classes.
  • More focus on core functionalities and design principles.
  • Easier refactoring due to less reliance on mocks.
  • Leads to highly integrated and maintainable codebase.
  • Debugging can be more challenging due to internal state focus.
  • May require additional effort for external system integration.
  • Projects prioritising maintainability and refactoring. - Teams comfortable with state-based testing.

Red: Write a Failing Test

Start by writing a test for the next bit of functionality you want to add. The test should fail because the functionality hasn't been implemented yet. This step ensures that the test is meaningful and that it accurately reflects the requirements of the functionality.

Green: Make the Test Pass

Write just enough code to make the test pass. The aim here is to quickly get to a passing state, without worrying about perfection. This often means the code isn't the cleanest, but it meets the criteria defined by the test.

Refactor: Clean Up the Code

Once the test is passing, look at the code you've written and consider how it can be improved without changing its functionality. This might involve removing duplication, improving names for clarity, or applying design patterns. The tests written in the Red stage ensure that this refactoring does not alter the behaviour of the code.

Writing tests after: The benefits of TDD are not the tests themselves, but the process of writing the tests first which results in better designed and more maintainable code.Overcomplicating tests: Tests that are too coupled to implementation are hard to maintain and become an impediment to change. Tests should be simple and focused on the behaviour of the system.Not considering the readability of tests: Making it difficult for others to understand the test suite or the intent behind code changes.

Was this page helpful?

Previous
API First Design
© ZeroBlockers, 2024. All rights reserved.