2

我有以下功能:

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

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

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

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返回结果。

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

4

1 回答 1

3

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

  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();
        })
       })
     });
    })
于 2016-05-03T20:15:04.910 回答