Sobes.tech
Middle+

What should an ideal approach to development through testing (TDD) look like?

sobes.tech AI

Answer from AI

The ideal approach to TDD is cyclical and consists of three main steps:

  1. Red:

    • Write a test that checks a functionality that does not exist yet (or does not work).
    • Run all tests. This new test should fail, which symbolizes the "red" state. It confirms that the test indeed checks for the absence of the required functionality.
  2. Green:

    • Write the minimal code necessary to pass this new test.
    • Run all tests again. All tests, including the new one, should pass, symbolizing the "green" state. The goal at this stage is to pass the tests, not to write perfect code.
  3. Refactor:

    • Improve the code written in the previous step. This includes cleaning up, increasing readability, eliminating duplication, improving structure – everything that does not break the tests.
    • Run all tests once more to ensure that the changes did not break existing functionality. Tests should remain "green".

After this, the cycle repeats for the next piece of functionality.

Key aspects of the ideal approach:

  • Small steps: Adding small, incremental changes both in tests and in code.
  • Fast feedback: Frequent test runs to quickly get information about the system's state.
  • Focus on behavior: Tests focus on the expected behavior of the system, not on internal implementation.
  • Code coverage: TDD naturally leads to high code coverage with tests.
  • Documentation: Tests serve as living documentation of how the code should work.
  • Confidence: Having a full set of passing tests provides confidence when refactoring and making changes.

Example of the Red/Green/Refactor cycle in JS:

  1. Red: Write a test for an addition function that does not exist yet.
    // math.test.js
    import { add } from './math'; // add function does not exist yet
    
    test('should add two numbers', () => {
      expect(add(1, 2)).toBe(3); // Test will fail because add is not defined
    });
    
  2. Green: Create the minimal function to pass the test.
    // math.js
    export function add(a, b) {
      return a + b; // Minimal code to pass the test
    }
    
    Run the tests. They will pass.
  3. Refactor: In this case, the code is simple enough that refactoring can be minimal or absent. If the function were more complex, this would be the place for optimization or readability improvements. Run the tests again. They should pass.

Then move on to the next requirement (e.g., handling negative numbers or non-numeric arguments) and start a new Red/Green/Refactor cycle.