使用jasmine测试JavaScript回调函数

时间:2016-05-03 15:48:53

标签: javascript jasmine jspec

我有以下功能:

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

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

getPersonData根据ID检索某人的信息。它通过传入id和successCallBack函数来调用retrieveData

retrieveData获取id和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方法。这是因为即使我模拟function(person)返回结果,也没有传入从成功callBack retrieveData传回的人员数据。

我的问题是: 这是测试callBack函数的正确方法吗?无论哪种方式,我做错了什么?

1 个答案:

答案 0 :(得分:3)

好的,所以茉莉花在很多细微的方面很棘手,我认为你的代码存在两个主要问题

  1. 你有太多的异步调用相互包装。这本身不是一个问题,但它使JASMINE的测试变得更加困难。例如,使用retrieveData函数调用executeRequest函数具有完全相同的参数但方式略有不同,这有什么意义。
  2. 我重写了你的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。为了测试Jasmine中的异步代码,您需要在测试中包含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();
            })
           })
         });
        })