使用jasmine测试JavaScript回调函数

Testing JavaScript callback functions with jasmine

本文关键字:回调 函数 JavaScript 测试 jasmine 使用      更新时间:2023-09-26

我有以下功能:

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)返回的人员数据没有被传入,即使我已经嘲笑retrieveData返回结果。

我的问题是:这是测试回调函数的正确方法吗?不管怎样,我做错了什么?

好的,所以jasmine在很多微妙的方面都很棘手,我认为你的代码有两个主要问题

  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.为了在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();
        })
       })
     });
    })