DEV Community

Edwin Torres
Edwin Torres

Posted on • Updated on

Simple Test-Driven Development (TDD) With Mocha and Node.js

Here is a quick tutorial on Test-Driven Development (TDD) with the Mocha test tool and Node.js.

Overview

Test-Driven Development, or TDD, is a programming style that includes three tightly integrated activities: coding, unit testing, and refactoring.

The TDD approach is a cycle:

Test-Driven Development

  1. RED/FAIL - Write one unit test for a single feature of the program, execute the test, and ensure that it fails. It should fail because the program feature has not been developed yet.
  2. GREEN/PASS - Write "just enough" code to make the test pass. The code may simply hard-code the correct output for a given input value.
  3. REFACTOR - Refactor the code with real logic until it passes the unit test. Implement the feature and remove the hard-coded result. Refactoring does not change the behavior of the program; the given input must still produce the expected output. Refactoring may also enhance a program or improve efficiency.
  4. Repeat.

TDD With Mocha and Node.js

Prerequisites

  • Download and install Node.js locally on your computer.
  • A terminal application: Terminal (macOS) or Git Bash (Windows).

Tutorial

Here is a new program feature to implement. The Restaurant Tip Calculator calculates tips for a restaurant bill.

Feature: Restaurant Tip Calculator
Scenario: Calculate a 20% restaurant tip.
When the restaurant bill is $100
Then the tip amount is $20

Here are steps that illustrate the TDD process:

  1. Open a terminal and go into a working folder:

    $  cd myfolder
    $
    
  2. Initialize the folder to use the Mocha test tool:

    $  git init .  # for Git versioning later
    $
    $  npm install -g mocha  # install mocha locally
    $
    $  mocha  # try mocha. It will fail; no tests yet...
    $  Error: No test files found: "test"         
    $
    
  3. From inside the myfolder folder, create a directory named test: mkdir test .

  4. Create an empty unit test program inside the test folder named TipTest.js: touch test/TipTest.js .

  5. In the myfolder folder create an empty program for the program we are testing: touch Tip.js .

  6. Run the Mocha test. We now have the minimal amount of code to have a failed test:

    $  mocha
    
      0 passing (2ms)
    
    $ 
    
  7. Add the first unit test to the TipTest.js program. This unit test checks the tip amount for a $100 amount. The correct/expected tip amount is $20:

    assert = require("assert");
    
    Tip = require("../Tip.js").Tip  // program to test
    
    // new unit test
    describe("Check tip amount", function() {
      describe("sending in 100", function() {
        it("should return 20", function() {
          var result = new Tip().CalculateTip(100);
          assert.equal(20,result);
        }); 
      }); 
    }); 
    
  8. RED: Add minimal code to the Tip.js program that initially fails the test:

    function Tip() {
    }
    
    Tip.prototype.CalculateTip = function(p1) {
    
      return 0; // hard-code a result that will FAIL
    
    }
    
    module.exports.Tip = Tip;
    
  9. Run the Mocha test. It will execute the test and fail, because the actual result of the program is 0, but the expected result is 20:

    $  mocha
    
      Check tip amount
        sending in 100
          1) should return 20
    
      0 passing (6ms)
      1 failing
    
      1) Check tip amount
           sending in 100
             should return 20:
    
          AssertionError [ERR_ASSERTION]: 20 == 0
          + expected - actual
    
          -20
          +0
    
          at Context.<anonymous> (test/TipTest.js:10:14)
          at processImmediate (internal/timers.js:456:21)
    
    $
    
  10. GREEN: Modify the Tip.js program to hard-code it to succeed:

    function Tip() {
    }
    
    Tip.prototype.CalculateTip = function(p1) {
    
      return 20; // hard-code a result that will SUCCEED
    
    }
    
    module.exports.Tip = Tip;
    
  11. Run the Mocha test again. This time it succeeds, because the actual and expected results are both 20:

    $  mocha
    
      Check tip amount
        sending in 100
          ✔ should return 20
    
      1 passing (4ms)
    
    $
    
  12. REFACTOR: Modify the code by implementing the correct logic for the Tip.js program:

    function Tip() {
    }
    
    Tip.prototype.CalculateTip = function(p1) {
    
      // NEW
      let tipAmount = p1 * 0.20
      return tipAmount;
    
    }
    
    module.exports.Tip = Tip;
    $
    
  13. Run the Mocha test and see it succeed with real, correct logic:

    $  mocha
    
      Check tip amount
        sending in 100
          ✔ should return 20
    
      1 passing (6ms)
    
    $  
    
  14. You have successfully used TDD to develop this first feature of the Tip Calculator program. Add more unit tests to test the program further or add new features.

Your turn

Create a new unit test for the Tip Calculator app that implements this feature:

Feature: Restaurant Tip Calculator
Scenario: Calculate a 25% restaurant tip.
When the restaurant bill is at least $200
Then the tip amount is 25% of the restaurant bill

Conclusion

This completes the TDD tutorial with Mocha. Note how TDD occurs in iterations. Establish a test that you expect to fail. Modify the test to make it succeed with the expected value. Finally, implement real logic in your program that passes the test. Repeat the process for each new feature of the program.

Thanks for reading!

Follow me on Twitter @realEdwinTorres for programming tips, software engineering content, and career advice. 😊

Top comments (1)

Collapse
 
skaunov profile image
skaunov

$ npm install -g mocha # install mocha locally

The comment contradicts with the command option. Did you mean "globally"?