【问题标题】:How can I test through a mocked promise with Mocha?如何通过 Mocha 的模拟承诺进行测试?
【发布时间】:2015-07-28 17:15:04
【问题描述】:

我的 node.js 代码是:

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;
    });
}

非常简单直接。我要测试的是这个函数的返回,正确解析,是一个匹配该格式的phoneNumbers数组。

sqlServer 是上面的require'd,我在这个文件中有很多东西 require'd。我使用mockery 将它们剔除,这似乎非常棒。

这是我的测试,到目前为止:

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();
    });


});

但是,在我的代码中,它永远不会超过 sqlServer.query。所以results 毫无意义。我还尝试了类似的方法:

response = methods.getPatientNotificationNumbers(1)

但是当我console.log(response)时,基本上是{state: 'pending'},我猜这是一个未解决的承诺。

所以我到处都是,我愿意使用任何使事情变得简单的库。我没有与mockerysinon 或其他任何人结婚。任何建议都会有所帮助。

谢谢!

【问题讨论】:

  • 你到底想测试什么? SQL 服务器还是只是then 中的方法?如果它只是then 中的方法,只需将其提取到命名函数中。你的承诺代码也是错误的。
  • 我的承诺代码有什么问题?
  • 你为什么还要延期?
  • 所以我可以解决来自存根函数的承诺
  • 您是否有任何理由需要异步解决延迟问题?

标签: node.js unit-testing mocking promise mocha.js


【解决方案1】:

所以另一种方法是使用rewirederide 的组合。

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();
    });
  });
}); 

这意味着您无需更改生产代码,并且可以使用以下方式轻松开始测试不满意的路径:

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();
    });
});

或者更简洁:

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

【讨论】:

    【解决方案2】:

    我会缩小一点并考虑测试策略。假设目标是在 sql server 之上测试您的模型层(方法)。它可以在不存根 sql server 的情况下完成。您的测试套件层可以有一组实用方法来创建、初始化和删除可以从 before、beforeEach 等调用的 db。 这样做的优点:

    1. 测试真实的产品代码路径更好(比存根代码路径)。
    2. 如果您怀疑底层错误会产生噪音,则使用存根会更好。 sqlserver 层可能是稳定的。
    3. 模型层似乎很简单,不需要单独测试。
    4. 如果您尝试在模型层中测试 sqlserver 故障处理,则使用存根是有意义的。然后存根层可以伪造这些错误——在模型代码中使用错误路径。

    这是基于您对问题的有限看法。如果还有更多。请分享,我们可以从那里拿走。

    【讨论】:

      【解决方案3】:

      在我看来,您的意图是测试您传递 .then() 方法的函数,而不是 sqlserver 库或它返回的实际承诺。我们可以假设这些已经过测试。

      如果是这种情况,您可以简单地分解该函数(从 SQL 结果中提取电话号码的函数)并独立测试它。

      您的代码将变成以下内容:

      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);
      }
      

      ...您的./getNumbers.js 文件看起来像:

      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;
      

      现在你可以独立测试了:

      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
      });
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-07-22
        • 1970-01-01
        • 2020-11-21
        • 1970-01-01
        • 1970-01-01
        • 2017-12-29
        • 2017-06-23
        相关资源
        最近更新 更多