One class unit-tests

Posted on

Problem

Its my first attempt to unit-test in Js. Not yet TDD.
What I can change?

EventsPersistancyService.js:

var Q = require('q');

var EventsPersistancyService = {
  accept: function acceptService(msg) {

    var worker_id = WorkerCacheService.get('some login');
    var app_category = AppCategoryService.get('some');

    var p = Q.all([worker_id, app_category]).then(function () {
      var content = msg.content.toString();
      content = JSON.parse(content);
      return Event.create(content);
    });

    return p;
  }
}

module.exports = EventsPersistancyService;

Unit tests:

"use strict";

var assert = require('assert');
var chai = require('chai');
var expect = chai.expect;
var chaiAsPromised = require('chai-as-promised');
var sinonChai = require("sinon-chai");
chai.use(chaiAsPromised);
chai.use(sinonChai);
var sinon = require('sinon');
var Q = require('q');


var TPL = {
};

describe('EventsPersistancyService', function () {

  describe('#accept', function () {

    var s1, s2, s3, s4;

    var message = {
      fields: null,
      properties: null,
      content: new Buffer(JSON.stringify(TPL))
    };

    beforeEach(function () {
      s1 = sinon.stub(WorkerCacheService, 'get').returns(Q.resolve(""));
      s2 = sinon.stub(AppCategoryService, 'get').returns(Q.resolve(""));
      s3 = sinon.stub(Event, 'create').returns(Q.resolve(1));
    });

    afterEach(function () {
      sinon.sandbox.restore();
      s1.restore();
      s2.restore();
      s3.restore();
    });

    it('should return error when accept param is null', function () {
      var res = EventsPersistancyService.accept(null);
      return expect(res).to.be.rejected;
    });

    it('should return resolve promise on non error situation', function () {
      var res = EventsPersistancyService.accept(message);
      return expect(res).to.be.not.rejected;
    });

    it('should call WorkerCacheService to get worker_id', function () {
      EventsPersistancyService.accept(message);
      return expect(s1).to.have.been.calledOnce;
    });

    it('should call AppCategoryService to get app_category', function () {
      EventsPersistancyService.accept(message).then();
      return expect(s2).to.have.been.calledOnce;
    });

    it('should call Event.create when all if ok', function () {
      EventsPersistancyService.accept(message).then(function () {
        expect(s4).to.have.been.calledOnce;
      }, function () {
        expect(s4).to.have.been.calledOnce;
      });
    });

    it('should reject when Event.create reject', function () {
      s3.restore();
      s3 = sinon.stub(Event, 'create').returns(Q.reject(1));
      var p = EventsPersistancyService.accept(message);
      return expect(p).to.be.rejected;
    });

    it('should reject when Event.create throw', function () {
      var p = EventsPersistancyService.accept({});
      return expect(p).to.be.rejected;
    });

    it('should reject when WorkerCacheService.get fails', function () {
      s1.restore();
      s1 = sinon.stub(WorkerCacheService, 'get').returns(Q.reject(''));
      var p = EventsPersistancyService.accept(message);
      return expect(p).to.be.rejected;
    });

    it('should reject when AppCategoryService.get fails', function () {
      s2.restore();
      s2 = sinon.stub(AppCategoryService, 'get').returns(Q.reject(''));
      var p = EventsPersistancyService.accept(message);
      expect(p).to.be.rejected;
    });

  });
});

Solution

Use sinon-promises to simplify this:

'use strict';
const chai = require('chai');
const sinon = require('sinon');
const sinonChai = require('sinon-chai');
const chaiAsPromised = require('chai-as-promised');
const sinonStubPromise = require('./..');

sinonStubPromise(sinon);

chai.use(chaiAsPromised);
chai.use(sinonChai);

const expect = chai.expect;
let stub;

describe('stubbing promises', () => {
  beforeEach(() => {
    stub = sinon.stub();
  });

  it('should not throw an error when invoked', () => {
    stub.returnsPromise();
  });

  it('should allow defining a resolve value', () => {
    stub.returnsPromise();
    stub.resolves(1);

    return expect(stub()).to.eventually.equal(1);
  });

  it('should allow defining a reject value', () => {
    stub.returnsPromise();
    const err = new Error();
    stub.rejects(err);

    return expect(stub()).to.eventually.be.rejectedWith(err);
  });

  it('should allow overwriting a resolves with a reject', () => {
    stub.returnsPromise();
    const err = new Error();
    stub.resolves(1);
    stub.rejects(err);

    return expect(stub()).to.eventually.be.rejectedWith(err);
  });

  it('should allow overwriting a reject with a resolves', () => {
    stub.returnsPromise();
    const err = new Error();
    stub.rejects(err);
    stub.resolves(1);

    return expect(stub()).to.eventually.equal(1);
  });

  it('should be last-write-wins', () => {
    stub.returnsPromise();
    stub.resolves(1);
    stub.resolves(2);
    stub.resolves(3);

    return expect(stub()).to.eventually.equal(3);
  });
});

References

Leave a Reply

Your email address will not be published. Required fields are marked *