Test Driven Design

From A Technological Wiki
Revision as of 11:31, 19 April 2025 by imported>Unknown user
Jump to navigation Jump to search

Test Driven Design

TDD is a software development methodology where you write tests before you write the actual code. The process can be summarized in three primary steps:

  • Red: Write a failing test.
  • Green: Write the minimum code to make the test pass.
  • Refactor: Refine the written code while ensuring that the test still passes.

Simple example of TDD using PHP

The Requirement

Suppose you need to write a function that adds two numbers.

Red: Write a Failing Test

Before writing the function, you write a test for it. You can use PHP's built-in PHPUnit framework for this.

// tests/AdderTest.php

use PHPUnit\Framework\TestCase;

class AdderTest extends TestCase
{
    public function testAdd()
    {
        $adder = new Adder();
        $result = $adder->add(1, 2);

        $this->assertEquals(3, $result);
    }
}

At this stage, if you run the test, it will fail because the Adder class and the add method don't exist yet.

Green: Write the Minimum Code to Make the Test Pass

Now, you'll write just enough code to make the test pass.

// src/Adder.php

class Adder
{
    public function add($a, $b)
    {
        return $a + $b;
    }
}

If you run the tests again, they should pass.

Refactor

In our case, the add method is already straightforward, so there may not be anything to refactor immediately. But suppose, in a more complex scenario, you realized that there's a more efficient algorithm or a cleaner way to structure your code. You'd make those changes and then run the tests again to ensure nothing broke.

Repeat

You'd repeat these steps for every new feature or function. For instance, if you wanted to add a subtraction method, you'd start by writing a test for it, then implement the method, then refactor if necessary.

Advantages of TDD in PHP

  • Early Bug Detection: Since you're continually testing while developing, you detect and fix bugs early in the development cycle.
  • Improved Code Quality: Writing tests first often leads to better-designed, cleaner, and more maintainable code.
  • Documentation: Tests serve as documentation. They show how the code is supposed to work and how to use it.
  • Refactoring Confidence: With a suite of tests, you can refactor or make changes to the codebase with confidence, knowing that if you introduce a regression, the tests will likely catch it. In practice, TDD requires discipline, as it might seem counter-intuitive initially. But, with time, many developers find that it improves their productivity and the quality of their output.

Behaviour Driven Design

BDD is a software development approach that extends Test-Driven Development (TDD) by using natural language descriptions (often following the format "Given-When-Then") to define the behavior of an application. BDD encourages collaboration between developers, QA, and non-technical participants in a software project.

rundown of the BDD process

  • Use natural language to describe a feature of the application.
  • Write scenarios for the feature using the "Given-When-Then" format.
  • Implement test cases based on those scenarios.
  • Run the tests (they should initially fail since there's no implementation yet).
  • Implement the feature.
  • Run tests again, and they should pass if the feature is correctly implemented.

simple example using BDD

  • Scenario: Implementing a function to add two numbers.
  • Feature Description:
Feature: Add two numbers
    In order to perform quick calculations
    As a user of the calculator app
    I want to be able to add two numbers

Scenario:

Scenario: Adding two positive numbers
    Given I have a number 5
    And I have another number 3
    When I add the two numbers
    Then I should get 8 as the result

Now, we can write a test for this scenario using Behat (a popular BDD tool for PHP):

// features/bootstrap/FeatureContext.php

use Behat\Behat\Context\Context;

class FeatureContext implements Context
{
    private $num1;
    private $num2;
    private $result;

    /**
     * @Given I have a number :arg1
     */
    public function iHaveANumber($arg1)
    {
        $this->num1 = $arg1;
    }

    /**
     * @Given I have another number :arg1
     */
    public function iHaveAnotherNumber($arg1)
    {
        $this->num2 = $arg1;
    }

    /**
     * @When I add the two numbers
     */
    public function iAddTheTwoNumbers()
    {
        $this->result = $this->num1 + $this->num2;
    }

    /**
     * @Then I should get :arg1 as the result
     */
    public function iShouldGetAsTheResult($arg1)
    {
        if ($this->result !== (int)$arg1) {
            throw new \Exception("Expected $arg1, but got {$this->result}");
        }
    }
}

This is a simple test, and in real-world scenarios, the behaviors and steps would be more complex. However, the main idea remains the same: Describe the feature in natural language, implement the tests, and then create the functionality.

Using BDD tools like Behat, combined with Mink (a web acceptance testing framework), you can also test web applications by simulating browser interactions, checking page contents, clicking links, and filling out forms. This brings BDD from simple unit tests to full-fledged feature tests, ensuring that the software behaves correctly from the user's perspective.