TDD follows a simple cycle known as Red-Green-Refactor:

  1. Red: Write a test that fails (because the feature isn’t implemented yet).
  2. Green: Write the minimum code necessary to pass the test.
  3. Refactor: Improve the code while keeping the tests passing.

This cycle encourages developers to focus on the requirements and design of their code, leading to a more robust application.

Setting Up Jasmine

To get started with Jasmine, you need to install it. You can do this via npm:

npm install --save-dev jasmine

After installation, initialize Jasmine in your project:

npx jasmine init

This command creates a spec directory, where you will write your tests, and a jasmine.json configuration file.

Example: Developing a Simple Calculator

Let's walk through a practical example of creating a simple calculator using TDD with Jasmine.

Step 1: Write the First Test (Red)

Create a new file in the spec directory called calculatorSpec.js. Here, we will write a test for an add function that we have not yet implemented.

describe("Calculator", function() {
    it("should add two numbers", function() {
        const calculator = new Calculator();
        expect(calculator.add(1, 2)).toBe(3);
    });
});

Step 2: Implement the Minimum Code (Green)

Now, create a Calculator.js file in the src directory and implement the add function to pass the test.

class Calculator {
    add(a, b) {
        return a + b;
    }
}

Step 3: Run the Test

Run your tests using the command:

npx jasmine

You should see that the test for the add function passes.

Step 4: Refactor (if necessary)

In this case, the code is already simple and clean, so refactoring may not be necessary. However, if you had complex logic, you would refine it while ensuring all tests still pass.

Adding More Functionality

Continuing with TDD, let’s add more operations to our calculator: subtraction, multiplication, and division.

Step 1: Write Tests for New Features

Update calculatorSpec.js to include tests for the new operations.

describe("Calculator", function() {
    let calculator;

    beforeEach(function() {
        calculator = new Calculator();
    });

    it("should add two numbers", function() {
        expect(calculator.add(1, 2)).toBe(3);
    });

    it("should subtract two numbers", function() {
        expect(calculator.subtract(5, 2)).toBe(3);
    });

    it("should multiply two numbers", function() {
        expect(calculator.multiply(3, 4)).toBe(12);
    });

    it("should divide two numbers", function() {
        expect(calculator.divide(8, 2)).toBe(4);
    });
});

Step 2: Implement the New Features

Add the new methods to Calculator.js.

class Calculator {
    add(a, b) {
        return a + b;
    }

    subtract(a, b) {
        return a - b;
    }

    multiply(a, b) {
        return a * b;
    }

    divide(a, b) {
        if (b === 0) {
            throw new Error("Cannot divide by zero");
        }
        return a / b;
    }
}

Step 3: Run the Tests Again

Execute the tests again:

npx jasmine

All tests should pass, confirming that the new functionality works as expected.

Best Practices for TDD in JavaScript

Best PracticeDescription
Write Clear and Concise TestsEnsure test descriptions are clear and indicate what is being tested.
Keep Tests IndependentEach test should be able to run independently without relying on others.
Use beforeEach for SetupUse beforeEach to set up common test data or state before each test runs.
Refactor RegularlyContinuously refactor code to improve clarity and maintainability.
Test Edge CasesAlways include tests for edge cases and potential error scenarios.

Conclusion

Test-Driven Development using Jasmine in JavaScript promotes better coding practices and leads to more reliable software. By following the Red-Green-Refactor cycle, developers can ensure that their code is well-tested and maintainable. This approach not only helps in catching bugs early but also in clarifying the requirements of the software being developed.

Learn more with useful resources: