【问题标题】:Testing pre-defined callback function with Mocha.js使用 Mocha.js 测试预定义的回调函数
【发布时间】:2017-07-07 02:52:13
【问题描述】:

我正在尝试为以下函数编写测试。

function services(api){
    request(`${api}?action=services`, function(err, res, body) {
        if (!err && res.statusCode === 200){
            var resJson = JSON.parse(body);
            var numberOfServices = resJson.length;
            console.log("Service called: services");
            console.log("-----------");
            for (i = 0; i < numberOfServices; i++){
                console.log("Service ID: " + resJson[i].service);
                console.log("Service Name: " + resJson[i].name);
                console.log("-----------");
            }
            return resJson;
        }
    }); 
}

测试是检查函数是否返回一个对象。 resJson 是被返回和测试的对象。

下面是使用 Mocha.js 和 Chai.js 断言库编写的测试用例。

var chai = require('chai');
var assert = chai.assert;
var sendRequest = require('../request');

describe('Test 1', function() {

    var api = 'http://instant-fans.com/api/v2';

    it('services() should return an object of services', function(done) {
        var object = sendRequest.services(api);
        assert.isObject(object);
    });

});

但是,当我运行测试时,它会失败并显示以下控制台输出。说resJson 是未定义的。我猜摩卡试图在函数services()返回对象之前断言resJson是一个对象,但我不知道如何解决这个问题。

 Test 1
    1) services() should return an object of services

 0 passing (27ms)
 1 failing

  1) Test 1 services() should return an object of services:
     AssertionError: expected undefined to be an object
      at Function.assert.isObject (node_modules/chai/lib/chai/interface/assert.js:555:35)
      at Context.<anonymous> (test/requestTest.js:11:16)

我尝试在网上搜索,我看到有人使用done() 方法解决了这个问题。但是,在我的情况下,由于我在 services() 函数中使用回调,所以这不起作用。

【问题讨论】:

    标签: javascript node.js testing asynchronous mocha.js


    【解决方案1】:

    您的代码看起来正在执行异步请求sendRequest.services(api);

    您需要做的是处理在 mocha 测试中可用的 done() 回调:it('services() should return an object of services', function(done) {})

    您需要做的是重写您的services 函数,因为它不正确。您不能从异步函数返回,异步函数通常基于 I/O,并且不会阻塞 Nodejs 主线程。为了让您的主线程访问该值,您必须传入一个回调函数,该函数将在该值可用后执行。

    function services(api, cb){
        request(`${api}?action=services`, function(err, res, body) {
            var resJson;
            if (!err && res.statusCode === 200){
                resJson = JSON.parse(body);
                var numberOfServices = resJson.length;
                console.log("Service called: services");
                console.log("-----------");
                for (i = 0; i < numberOfServices; i++){
                    console.log("Service ID: " + resJson[i].service);
                    console.log("Service Name: " + resJson[i].name);
                    console.log("-----------");
                }
            }
            if (cb) {
                cb(err, resJson);
            }
        }); 
    }
    

    然后像这样重写你的测试:

    describe('Test 1', function() {
        var api = 'http://instant-fans.com/api/v2';
    
        it('services() should return an object of services', function(done) {
            sendRequest.services(api, function(resJson) {
                assert.isObject(resJson);
                done();
            });
        });
    
    });
    

    我会更进一步,将错误传递给回调函数(这在 nodejs 中很常见):

    cb(err, resJson);
    

    您的测试可以打印错误以便更好地调试:

    sendRequest.services(api, function(err, resJson) {
        if (err) {
            console.error(err);
        }
        assert.isObject(resJson);
        done();
    });
    

    【讨论】:

      【解决方案2】:

      我建议你阅读这篇关于异步函数使用的question


      您不能像在var object = sendRequest.services(api) 中那样将异步函数调用分配给变量。您需要使用callback,应将其作为参数添加到services 函数中

      function services(api, callback){
          // your logic here
      }
      

      您可以在services 函数中调用callback(resJson) 而不是执行return resJson。然后,在您的测试中,您需要调用services,第二个参数是function(result)

      sendRequest.services(api, function(result){
          assert.isObject(result);
      });
      

      编辑

      这就是你的services 函数的样子

      function services(api, callback){
          request(`${api}?action=services`, function(err, res, body) {
              if (!err && res.statusCode === 200){
                  var resJson = JSON.parse(body);
                  var numberOfServices = resJson.length;
                  console.log("Service called: services");
                  console.log("-----------");
                  for (i = 0; i < numberOfServices; i++){
                      console.log("Service ID: " + resJson[i].service);
                      console.log("Service Name: " + resJson[i].name);
                      console.log("-----------");
                  }
                  callback(resJson);
              }
          }); 
      }
      

      【讨论】:

      • 我需要对services() 函数进行更改吗?
      • 是的,正如我所说,你应该使用return resJson 而不是callback(resJson)。这将确保您完成断言。我用更新的services 函数编辑了答案
      • 啊,我第一次遇到这种情况,谢谢! :)
      猜你喜欢
      • 2015-07-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-12-10
      • 1970-01-01
      • 2019-09-21
      • 1970-01-01
      相关资源
      最近更新 更多