2016-05-03 6 views
1

У меня есть следующие функции:Тестирование JavaScript функции обратного вызова с жасмином

function getPersonData(id) { 
    retrieveData(
    id, 
    function(person) { 
     if(person.name) { 
     displayPerson(person); 
     } 
    } 
} 

function retrieveData(id, successCallBack) { 
    executeRequest(id, { 
     success: successCallBack 
    }); 
} 

getPersonData извлекает информацию человека на основе идентификатора. Он, в свою очередь, вызывает retrieveData, передавая функции id и successCallBack.

retrieveData принимает идентификатор и successCallBack и вызывает другую функцию, executeRequest, которая получает данные и передает объект person.

Я пытаюсь проверить getPersonData и имеют следующие спецификации настройки

describe("when getPersonData is called with the right person id", function() { 
    beforeEach(function() { 
    spyOn(projA.data, "retrieveData").and.returnValue(
     { 
     'name': 'john' 
     } 
    ); 
    spyOn(projA.data, "displayPerson"); 
    projA.data.getPersonData("123"); 
    }); 

    it("displays the person's details", function() { 
    expect(projA.data.displayPerson).toHaveBeenCalled(); 
); 
}); 

Но когда спецификации выполняется метод displayPerson не называется. Это связано с тем, что данные человека, переданные из успешного вызова CallBack function(person), не передаются, хотя я издевался над retrieveData, чтобы вернуть результат.

Мой вопрос: Это правильный способ проверить функции callBack? В любом случае, что я делаю неправильно?

+0

Думаю, использование функции 'returnValue' для функции, которая не возвращает значение, не будет работать. Есть ли альтернативы? – user12222

+0

Я решил переместить 'function (person) { if (person.name) { displayPerson (person); } } 'к новому методу, который поможет при тестировании. Но мне все равно хотелось бы знать, как можно было проверить предыдущий код. – user12222

ответ

2

Итак, жасмин сложен в много тонких способах, и я думаю, что есть две основные проблемы, связанные с вашим кодом

  1. У вас есть слишком много асинхронных вызовов, завернутых в друге друг. Это само по себе не проблема, но делает тестирование в JASMINE ад намного сложнее. Например, в чем смысл функции retrieveData, которая просто вызывает функцию executeRequest с точно такими же параметрами, но несколько иначе.

Я переписал свои getPersonData, чтобы быть, как это

function getPersonData(id) { 
    // this is needed to properly spy in Jasmine 
    var self = this; 

    //replaced retrieveData with just execute request 
    // self is required to properly spy in Jasmine 
    self.executeRequest(id, { 
    success: function(person) { 
    if (person.name) { 
     self.displayPerson(person); 
    } 
    } 
    }) 
} 

//I don't know what exactly executeRequest does 
//but I took the liberty to just make it up for this example 
function executeRequest(id, callback) { 
callback.success({ 
    name: id 
    }); 
} 

//I also assumed that projA would look something like this 
var projA = { 
data: { 
    getPersonData: getPersonData, 
    retrieveData: retrieveData, 
    displayPerson: displayPerson, 
    executeRequest: executeRequest 
} 
}; 

2. Для проверки асинхронного кода в жасмин, вам необходимо включить done обратного вызова с тестом. Кроме того, если вы ожидаете, что функция обратного вызова будет срабатывать автоматически, вам необходимо установить ее в пределах функции setTimeout, иначе она никогда не будет срабатывать. Вот скопированный пример:

describe("when getPersonData is called with the right person id", function() { 
    beforeEach(function() { 
     //you should not spyOn retriveData or executeCode because it will override the function you wrote and will never call displayPerson 

     // you should only have spies on the methods you are testing otherwise they will override other methods 
     spyOn(projA.data, "displayPerson"); 
    }); 

    it("displays the person's details", function(done) { 
     // it's better to call the function within specific test blocks so you have control over the test 
     projA.data.getPersonData("123"); 

     // at this point, it will just have called the getPersonData but will not call executeRequest 
     setTimeout(function() { 
     //this block will just call executeRequest 
     setTimeout(function() { 
     //this block will finally call displayPerson 
     expect(projA.data.displayPerson).toHaveBeenCalled(); 

     //tell jasmine the test is done after this 
     done(); 
     }) 
     }) 
    }); 
    }) 
Смежные вопросы