2017-02-17 6 views
0

Я пытаюсь написать тест для следующей функции.Тестирование предопределенной функции обратного вызова с помощью Mocha.js

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 не определено. Я предполагаю, что Mocha пытается утверждать, что resJson является объектом, перед тем как функция services() возвращает объект, но я не уверен, как это решить.

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().

ответ

0

Я предлагаю вам прочитать эту question относительно использования асинхронных функций


Вы не можете назначить вызов асинхронной функции в переменной так же, как вы делаете в var object = sendRequest.services(api). Вы должны использовать callback, который должен быть добавлен в качестве параметра для функции services

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

И вместо исполняющей return resJson вы можете вызвать callback(resJson) в функции services. Затем, в тесте, вы должны вызвать 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); 
     } 
    }); 
} 
+0

Мне нужно будет внести изменения в функцию 'services()'? –

+0

Да, как я уже сказал, вместо «return resJson» вы должны сделать callback (resJson) '. Это гарантирует, что это утверждение будет выполнено. Я отредактировал ответ с обновленной функцией 'services' – piotrbienias

+0

А это первый раз, когда я столкнулся с этим, спасибо! :) –

0

Ваш код похоже, что он выполняет асинхронный запрос sendRequest.services(api);

Что вам нужно сделать, это обрабатывать 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(); 
});