Javascript 使用Jasmine模拟多个方法调用

Javascript 使用Jasmine模拟多个方法调用,javascript,unit-testing,jasmine,Javascript,Unit Testing,Jasmine,我正在尝试用JavaScript编写一个测试,我正在测试的方法会调用两个方法(model.expandChildren()和view.update();) 我曾尝试使用Jasmine specs来编写对spyOn的view和model函数的测试,但似乎在给定的测试中只能有一个spy。似乎我在这里遗漏了一些重要的东西,应该有一种方法可以使用spies模拟多个方法调用,因为我的函数需要进行这两个调用 我希望我的规范能够按照下面的方式运行,但它目前只通过第一个测试(第一个spy按预期运行),第二个测试

我正在尝试用JavaScript编写一个测试,我正在测试的方法会调用两个方法(model.expandChildren()和view.update();)

我曾尝试使用Jasmine specs来编写对spyOn的view和model函数的测试,但似乎在给定的测试中只能有一个spy。似乎我在这里遗漏了一些重要的东西,应该有一种方法可以使用spies模拟多个方法调用,因为我的函数需要进行这两个调用

我希望我的规范能够按照下面的方式运行,但它目前只通过第一个测试(第一个spy按预期运行),第二个测试失败,因为Jasmine正在尝试运行实际的函数,而不是spied函数:

var model = GRAPH.model;
var view = GRAPH.view;
var app = RV.graph;

describe('#expandChildren', function() {

    beforeEach(function() {
        // first spy, all good
        spyOn(model, 'expandChildren').and.callFake(function() {
          return new Promise(function(resolve) {
            resolve(testResponse);
          });
        });
        // second spy doesn't work because Jasmine only allows 1
        spyOn(view, 'update');
        app.expandChildren();
    });

    // passing test
    it('calls model.expandChildren', function() {
        expect(model.expandChildren).toHaveBeenCalled();
    });

    // failing test that runs the REAL view.update method
    it('calls view.update', function() {
        expect(view.update).toHaveBeenCalled();
    });
});

有没有办法用Jasmine做到这一点?

请记住,您使用的是异步调用。第一个调用是同步的,因此会被记录,但第二个调用只会在稍后发生。当事情发生时,给自己一些控制权。我通常使用这样的模式:

describe('#expandChildren', function() {
    var resolver;

    it('calls model.expandChildren', function(done) {
        spyOn(model, 'expandChildren').and.callFake(function() {
          return new Promise(function(resolve) {
            resolver = resolve;
          });
        });
        spyOn(view, 'update');

        app.expandChildren();

        expect(model.expandChildren).toHaveBeenCalled();
        expect(view.update).not.toHaveBeenCalled();

        resolver();
        done();

        expect(view.update).toHaveBeenCalled();
    });
});

这样,只有在承诺得到解决并且调用了
done()
之后,规范才会运行。

解决肯定是另一个问题,但即使是
done()
我的第二次测试仍然失败。我可能有误解,但我的印象是,每个描述块只能使用一个间谍,即使测试套件中有多个间谍。可以创建的间谍数量没有限制。无论如何,在创建时同步解决承诺可能还为时过早。我从未尝试过这种模式,但总是手工解决。通过这种方式,您可以额外测试异步代码,该代码只在稍后执行。见编辑后的答案。
describe('#expandChildren', function() {
    var resolver;

    it('calls model.expandChildren', function(done) {
        spyOn(model, 'expandChildren').and.callFake(function() {
          return new Promise(function(resolve) {
            resolver = resolve;
          });
        });
        spyOn(view, 'update');

        app.expandChildren();

        expect(model.expandChildren).toHaveBeenCalled();
        expect(view.update).not.toHaveBeenCalled();

        resolver();
        done();

        expect(view.update).toHaveBeenCalled();
    });
});