How can I check through a mocked promise using Mocha?

My node.js code:

function getPatientNotificationNumbers(patientId) {
    patientId = patientId && patientId.toString();

    var sql = "SELECT * FROM [notification_phone_number] ";
    sql += "WHERE patient_id = " + escapeSql(patientId);
    return sqlServer.query(sql).then(function(results) {
        var phoneNumbers = _.map(results[0], function (result) {
            var obj = {
                id: result.id,
                phoneNumber: result.phone_number,
                isPrimary: result.is_primary,
                isVerified: result.is_verified,
                patientId: result.patient_id
            }
            return obj;
        });

        return phoneNumbers;
    });
}

      

Quite simple and straightforward. I want to check that the return of this function, correctly resolved, is an array phoneNumbers

conforming to this format.

sqlServer

above require

'd and I have a ton of require

' d's' in this file. To turn them off, I use mockery

which seems to be quite large.

Here's my test so far:

before(function() {
    deferred = Q.defer();
    mockery.enable();
    moduleConfig.init();
    mockery.registerSubstitute('moment', moment);
    mockery.registerAllowable('../../util');

    mockStubs.sqlServer = {
        query: sinon.stub().returns(deferred.promise)
    }

    mockery.registerMock('../../db/sqlserver', mockStubs.sqlServer);

    methods = require('../../../rpc/patient/methods');
});

beforeEach(function() {
    deferred = Q.defer();
})

it('should get the patient notification numbers', function(done) {
    // sinon.spy(sqlServer, 'query').and.returnValue(deferred.promise);
    deferred.resolve('here we go');
    methods.getPatientNotificationNumbers(1).then(function(result) {
        console.log(result);
        done();
    });


});

      

However, in my code, it never misses sqlServer.query

. So results

meaningless. I have also tried something like:

response = methods.getPatientNotificationNumbers(1)

but when I do console.log(response)

, it's basically {state: 'pending'}

what I think is an unresolved promise.

So, I am all over the place and I am open to using any library. I am not married to mockery

, sinon

or anything else. Any suggestions would help.

Thank!

+3


source to share


3 answers


So another approach is to use a combination of rewire and deride .

var should = require('should-promised');                                                                                                                                                        
var rewire = require('rewire');                                                                                                                                                                
var Somefile = rewire('./path/to/file');                                                                                                                                                       
var deride = require('deride');                                                                                                                                                                

var sut, mockSql;                                                                                                                                                                              
before(function() {                                                                                                                                                                            
  mockSql = deride.stub(['query']);                                                                                                                                                            
  Somefile.__set__('sqlServer', mockSql);                                                                                                                                                      
  sut = new Somefile();                                                                                                                                                                        
});                                                                                                                                                                                            

describe('getting patient notification numbers', function() {                                                                                                                                  
  beforeEach(function() {                                                                                                                                                                      
    mockSql.setup.query.toResolveWith(fakeSqlResponse);                                                                                                                                        
  });                                                                                                                                                                                          

  it('resolves the promise', function() {
    sut.getPatientNotificationNumbers(id).should.be.fulfilledWith(expectedPhoneNumbers);
  });

  it('queries Sql', function(done) {
    sut.getPatientNotificationNumbers(id).then(function() {
      mockSql.expect.query.called.once();
      done();
    });
  });
}); 

      

This will mean that you don't need to change production code and you can easily start testing unlucky paths using something like this:



it('handles Sql errors', function(done) {
  mockSql.setup.query.toRejectWith(new Error('Booom'));
  sut.getPatientNotificationNumbers(id)
    .then(function(){
      done('should not have resolved');
    })
    .catch(function(e) {
       e.should.be.an.Error;
       e.message.should.eql('Booom');
       done();
    });
});

      

Or even more succinctly:

it('handles Sql errors', function(done) {
  mockSql.setup.query.toRejectWith(new Error('Booom'));
  sut.getPatientNotificationNumbers(id).should.be.rejectedWith(/Booom/);
});

      

+4


source


I would zoom out a bit and think about a testing strategy. Suppose the goal is to test your model layer (s) on top of sql server. This can be done without creating a sql server. Your test suite layer can have a set of utility methods to create, initialize and discard the db, which can be called before, beforeEach, etc. The pros of this:

  • Testing the actual product code is better (than a numbered code path).
  • Stubbing is best if you suspect underlying layer errors are generating noise. Sqlserver level is likely to be stable.
  • The model layer looks simple enough that it doesn't require testing in isolation.
  • Stubbing makes sense if you are trying to test the sqlserver error work in your model level. Then the stub layer can fake such errors - use error paths in the model code.


This is based on a limited view of your problem. If this is more. Pl is divided and we can take it from there.

+2


source


It looks to me like you intend to test the function passing the method .then()

, not the library sqlserver

, and the actual promise it returns. We can assume that they have already been tested.

If so, you can simply drop that function (the one that extracts phone numbers from the SQL result) and test it independently.

Your code will become something like:

var getNumbers = require('./getNumbers');
function getPatientNotificationNumbers(patientId) {
    patientId = patientId && patientId.toString();

    var sql = "SELECT * FROM [notification_phone_number] ";
    sql += "WHERE patient_id = " + escapeSql(patientId);
    return sqlServer.query(sql).then(getNumbers);
}

      

... and your file ./getNumbers.js

will look something like this:

function getNumbers(results) {
    var phoneNumbers = _.map(results[0], function (result) {
        var obj = {
            id: result.id,
            phoneNumber: result.phone_number,
            isPrimary: result.is_primary,
            isVerified: result.is_verified,
            patientId: result.patient_id
        }
        return obj;
    });

    return phoneNumbers;
}

module.exports = getNumbers;

      

Now you can check it yourself:

var getNumbers = require('../path/to/getNumbers');

...

it('should get the patient notification numbers', function(done) {
    var sampleResults = [ ... ]; // sample results from sqlServer
    var phoneNumbers = getNumbers(sampleResults);
    assert(...); // make what ever assertions you want
});

      

+1


source







All Articles