Testing

Mocha is used as the test framework along with should.js and supertest. The principles behind why we use testing in our apps along with some basics on Mocha are covered in Chapter 1, Building a Basic Express Site. Testing supertest lets you test your HTTP assertions and testing API endpoints.

The tests are placed in the root folder /test. Tests are completely separate from any of the source code and are written to be readable in plain English, that is, you should be able to follow along with what is being tested just by reading through them. Well-written tests with good coverage can serve as a readme for its API, since it clearly describes the behavior of the entire app.

The initial setup to test our movies API is the same for both /test/actors.js and /test/movies.js and will look familiar if you have read Chapter 1, Building a Basic Express Site:

var should = require('should'); var assert = require('assert');
var request = require('supertest');
var app = require('../src/lib/app');

In src/test/actors.js, we test the basic CRUD operations: creating a new actor object, retrieving, editing, and deleting the actor object. An example test for the creation of a new actor is shown as follows:

  describe('Actors', function() { 

  describe('POST actor', function(){
    it('should create an actor', function(done){ 
      var actor = {
        'id': '1',
        'name': 'AxiomZen', 'birth_year': '2012',
       };

       request(app)
       .post('/actors')
       .send(actor)
       .expect(201, done)
    });

We can see that the tests are readable in plain English. We create a new POST request for a new actor to the database with the id of 1, name of AxiomZen, and birth_year of 2012. Then, we send the request with the .send() function. Similar tests are present for GET and DELETE requests as given in the following code:

  describe('GET actor', function() {
    it('should retrieve actor from db', function(done){ 
      request(app)
      .get('/actors/1')
      .expect(200, done);
    });
  describe('DELETE actor', function() {
    it('should remove a actor', function(done) { 
      request(app)
      .delete('/actors/1')
     .expect(204, done);
    });
  });

To test our PUT request, we will edit the name and birth_year of our first actor as follows:

  describe('PUT actor', function() {
    it('should edit an actor', function(done) { 
      var actor = {
        'name': 'ZenAxiom', 
        'birth_year': '2011'
      };

      request(app)
      .put('/actors/1')
      .send(actor)
      .expect(200, done);
    });

    it('should have been edited', function(done) { 
      request(app)
      .get('/actors/1')
      .expect(200)
      .end(function(err, res) { 
        res.body.name.should.eql('ZenAxiom'),
        res.body.birth_year.should.eql(2011);
        done();
      });
     });
  });

The first part of the test modifies the actor name and birth_year keys, sends a PUT request for /actors/1 (1 is the actors id), and then saves the new information to the database. The second part of the test checks whether the database entry for the actor with id 1 has been changed. The name and birth_year values are checked against their expected values using .should.eql().

In addition to performing CRUD actions on the actor object, we can also perform these actions to the movies we add to each actor (associated by the actor's ID). The following snippet shows a test to add a new movie to our first actor (with the id of 1):

  describe('POST /actors/:id/movies', function() { 
    it('should successfully add a movie to the actor',function(done) { 
      var movie = {
        'id': '1',
        'title': 'Hello World', 
        'year': '2013'
      }
      request(app)
      .post('/actors/1/movies')
      .send(movie)
      .expect(201, done)
      });
    });

    it('actor should have array of movies now', function(done){ 
      request(app)
      .get('/actors/1')
      .expect(200)
      .end(function(err, res) { 
      res.body.movies.should.eql(['1']); 
      done();
     });
    });
  });

The first part of the test creates a new movie object with id, title, and year keys, and sends a POST request to add the movies as an array to the actor with id of 1. The second part of the test sends a GET request to retrieve the actor with id of 1, which should now include an array with the new movie input.

We can similarly delete the movie entries as illustrated in the actors.js test file:

  describe('DELETE /actors/:id/movies/:movie_id', function() { 
    it('should successfully remove a movie from actor', function(done){
      request(app)
      .delete('/actors/1/movies/1')
      .expect(200, done);
    });

    it('actor should no longer have that movie id', function(done){
      request(app)
      .get('/actors/1')
      .expect(201)
      .end(function(err, res) { 
        res.body.movies.should.eql([]); 
        done();
      });
    });
  });

Again, this code snippet should look familiar to you. The first part tests that sending a DELETE request specifying the actor ID and movie ID will delete that movie entry. In the second part, we make sure that the entry no longer exists by submitting a GET request to view the actor's details where no movies should be listed.

In addition to ensuring that the basic CRUD operations work, we also test our schema validations. The following code tests to make sure two actors with the same ID do not exist (IDs are specified as unique):

  it('should not allow you to create duplicate actors', function(done) {
    var actor = { 
      'id': '1',
      'name': 'AxiomZen', 
      'birth_year': '2012',
    };

    request(app)
    .post('/actors')
    .send(actor)
    .expect(400, done);
  });

We should expect code 400 (bad request) if we try to create an actor who already exists in the database.

A similar set of tests is present for tests/movies.js. The function and outcome of each test should be evident now.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.60.249