Customer Module Unit Tests – Node.js API with TDD Tutorial

This post contains all the unit test cases for the  customer.module.js file to test and write the functional code for it’s expected behaviour.

Unit Test 5: Reading CustomerModule Function

As a first test, we will start with the customer.module.js file where we will test for the CustomerModule function which is exposed as a module. 

Test Script

Let’s add the initial test file content in the customer.module.spec.js file, just like the mongodb.module.js file. With chai and expect modules loaded at the beginning, the main test suite is added as below. We are loading the custom.module.js file into a variable CustomerModule by requiring that javascript file. 

var chai = require('chai');
var expect = chai.expect;

var CustomerModule = require('../../../modules/customer/customer.module');

describe('CustomerModule', function () {

});

Inside this test suite, we will add the new test suite to test the CustomerModule function. Since we already loaded the module file, let’s write a spec that will expect for the CustomerModule to be a function. 

describe('customer.module file', function () {
 it('should confirm CustomerModule function exist', function () {
        expect(CustomerModule).to.be.a('function');
  });
});

If we run the mocha test runner now, it will show one unit test failure as we haven’t written anything in the customer.module.js yet. 

UnitTest 5 - Reading CustomerModule Function - Failed
Unit Test 5: Reading CustomerModule Function – Failed

Code

To make the above spec to pass, we will develop the expected behaviour which is the module should be returning a function. As usual, we will start with the initial javascript content which is an IIFE code block. Also, create an empty function called ‘init’ and assign it to the module.exports statement. This statement will expose the init function as a module for the customer.module.js file.

(function () {
    'use strict';

    module.exports = init;

    function init() {
    }

})();

As we have written the minimal code that satisfies the expectation of the spec that we just wrote, running the unit test will result in all the passing test suites.

Unit Test 5 - Reading CustomerModule Function - Passed
Unit Test 5: Reading CustomerModule Function – Passed

Unit Test 6: CustomerModule Function Returns Object

Continuation of the above test, we will add one more spec to test that the CustomerModule function returns an object. This function is where will add the attributes for the rest of the files in this module.

Test Script

Below is the spec with the expectation of the CustomerModule function to return an object when it’s called. Add this spec just below the first spec in the customer.module.spec.js file.

it('should confirm CustomerModule function returns an object', function () {
    expect(CustomerModule()).to.be.a('object');
});

If we run the mocha test runner now, it will show one unit test failure as we haven’t written any code for the current test case in the customer.module.js yet. 

Unit Test 6: CustomerModule Function Returns Object - Failed
Unit Test 6: CustomerModule Function Returns Object – Failed

Code

For making the CustomerModule function to return the object as a result, we need to make the init function in the customer.module.js to return an object as this is the function exposed with the module.

Below is the update code for the init function to meet the spec’s expectation. It will make the new test to pass successfully.

function init() {
    return {}
}

As we have written the minimal code that satisfies the expectation of the spec that we just wrote, running the unit test will result in all the passing test suites.

Unit Test 6: CustomerModule Function Returns Object - Passed
Unit Test 6: CustomerModule Function Returns Object – Passed

Unit Test 7: Reading CustomerController Function

Next spec that we are going to write will test for the CustomerController attribute which is part of the CustomerModule function’s returned object.

Test Script

As mentioned above, this test will be calling the CustomerModule function and expecting that the CustomerController attribute of function type which will be part of the response.

it('should confirm CustomerController function exist', function () {
    expect(CustomerModule().CustomerController).to.be.a('function');

});

Running the test suites will yield an error as the test result as shown in the below screenshot.

Unit Test 7: Reading CustomerController Function - Failed
Unit Test 7: Reading CustomerController Function – Failed

Code

This test requires changes in two files: customer.controller.js and customer.module.js. 

As explained at the beginning of this section, CustomerController will expose the Router object which is part of the ExpressJS framework. To make this test pass, let’s add the below code block in the customer.controller.js

(function () {
    'use strict';

    var express = require('express');
    var router = express.Router();

    module.exports = router;

})();

What we are doing here is, we are creating a router object from the express module and exporting it by assigning to the module.exports object. So, when this file is loaded to any variable in other files, it will load the router object itself.

Here is the next change needed for making that spec to pass. In the response object of the customer.module.js file, we need to add an attribute which loads the customer.controller.js file by requiring it. It will pass the latest spec as it satisfies the expectation.

function init() {
    return {
        CustomerController: require('./customer.controller')
    }
}

As shown in the below screenshot, the latest unit test will be passing successfully now.

Unit Test 7: Reading CustomerController Function - Passed
Unit Test 7: Reading CustomerController Function – Passed

Unit Test 8: Reading CustomerMiddleware Object

Just like the above test, we can add a new spec to test the CustomerMiddleware object from the CustomerModule call.

Test Script

Below is the spec for testing the CustomerMiddleware object.

it('should confirm CustomerMiddleware object exist', function () 	{	
    expect(CustomerModule().CustomerMiddleware).to.be.a('object');
});

This test script will be causing the below error as the functional code to satisfy this test case is not yet written.

Unit Test 8: Reading CustomerMiddleware Object - Failed
Unit Test 8: Reading CustomerMiddleware Object – Failed

Code

This spec also warrants changes in two files: customer.middleware.js and customer.module.js. As the changes in the first file exports an object and latter file exposes that object through an attribute CustomerMiddleware.

Here is the code for the customer.middleware.js. It is the basic functional code for the module file as we have seen in the earlier post.

(function () {
    'use strict';

    module.exports = {};

})();

We will add the below line in the init function’s response object in the customer.module.js file, just below the CustomerController attribute. 

CustomerMiddleware: require('./customer.middleware')

Add the necessary comma at the end of each attribute’s declaration to avoid any javascript error. We will get the spec for this functional code passed when we run the mocha test runner.

Unit Test 8: Reading CustomerMiddleware Object - Passed
Unit Test 8: Reading CustomerMiddleware Object – Passed

Unit Test 9: Reading CustomerService Object

This test is testing the CustomerService object returned as one of the attributes of the CustomerModule function call.

Test Script

Below is the spec for testing the CustomerService object.

it('should confirm CustomerService object exist', function () {
    expect(CustomerModule().CustomerService).to.be.a('object');
});

This test script will be causing the below error as the functional code to satisfy this test case is not yet written.

Unit Test 9: Reading CustomerService Object - Failed
Unit Test 9: Reading CustomerService Object – Failed

Code

Both customer.service.js and customer.module.js files need to be updated for this test as well. We will update the customer.service.js with the essential javascript content just like the customer.middleware.js as it needs to export an object.

(function () {
    'use strict';

    module.exports = {};

})();

Also, let’s update the customer.module.js file’s init function with the below line in the response object.

CustomerService: require('./customer.service')

Just like the other specs, this one will also run successfully now while testing.

Unit Test 9: Reading CustomerService Object - Passed
Unit Test 9: Reading CustomerService Object – Passed

Unit Test 10: Reading CustomerModel Function

Finally, we have come to the last spec of this section. Here we will test for the CustomerModel function.

Test Script

Below is the spec for testing the CustomerModel object when calling the CustomerModule function.

it('should confirm CustomerModel function exist', function () {
    expect(CustomerModule().CustomerModel).to.be.a('function');
});

Running the test suites will yield an error as the test result as shown in the below screenshot.

Unit Test 10: Reading CustomerModel Function - Failed
Unit Test 10: Reading CustomerModel Function – Failed

Code

CustomerModel is the class definition which is compiled from the Mongoose’s Schema definition. Customer document in the MongoDB database is the instance of the CustomerModel.  The schema for the customer maps to the Customers MongoDB collection and defines the shape of the customer documents within that collection.

At first, we will load the mongoose module to start with for defining the CustomerModel in the default IIFE code block as below. From the mongoose, we need to get the Schema constructor which will be used to define the CustomerSchema with required attributes for the customer document. 

Below is the complete content of the customer.model.js file.

(function () {
    var mongoose = require('mongoose');

    var Schema = mongoose.Schema;

    var CustomerSchema = new Schema({
        firstName: {
            type: String,
            required: true
        },
        lastName: {
            type: String,
            required: true
        },
        email: {
            type: String,
            required: true
        },
        phoneNumber: {
            type: Number,
            required: true
        },
        address: String,
        city: String,
        state: String,
        zipCode: String,
        country: String
    });

    module.exports = mongoose.model('customers', CustomerSchema);
})();

The attributes are defined in the schema as per the requirement specification of the customer details that we have seen in the requirements post. Each attribute is specified with the type of SchemaType available in the mongoose. 

Below is the permitted SchemaTypes with which we can assign the attribute’s type. 

  1. String
  2. Number
  3. Date
  4. Buffer
  5. Boolean
  6. Mixed
  7. ObjectId
  8. Array

We can also declare whether the attribute is required or not required with the ‘required’ flag. When an attribute is declared with required as true, if we save the document without that particular attribute, MongoDB will throw an exception of missing attribute. This flag will enforce the validation of that attribute’s availability in the document while saving in the database.

Once the structure of the document is defined with the Schema constructor with all the attributes, we need to compile it to make a Model out of it. The below line does the compilation of the Schema to create the Model.

module.exports = mongoose.model('customers', CustomerSchema);

What happens with this line is, mongoose.model() is copying the Schema definition and provides an interface to the MongoDB collection called ‘customers’ which is the first parameter of this function. This model will be used to create document instances. 

If we pass the first parameter, the collection name, as the singular form, Mongoose will convert to the plural form of the collection name while it creates it in the MongoDB. Preferably, always try to use the plural form for the collection name to avoid any automatic conversion issue.

The above statement will be returning the Model constructor of a function type. We are assigning the function to the module.exports object. This assignment will satisfy the specs’ expectation of a function type to be returned for the CustomerModule().CustomerModel statement after the next described change.

The second change for this spec is to be done in the customer.module.js file where the CustomerModel attribute will be loaded with the customer.model.js file as below.

CustomerModel: require('./customer.model')

With this line of code, we have completed the test suite for the customer.module.js file. Below is the mocha test result for this module’s test suite. All the specs should be running successfully.

Unit Test 10: Reading CustomerModel Function - Passed
Unit Test 10: Reading CustomerModel Function – Passed

You can check out the below link to the source code for this step in GitHub.

GitHub – Step 04 – Customer Module Setup

Please check out the index page for this Node.js RESTful API development with TDD approach tutorial with all the posts in sequence in one place.

This blog post is an excerpt from the book Building Node.js REST API with TDD approach. Please check out the link for more information.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.