我有一些紧密耦合的传统代码,我想用测试覆盖它。有时候很重要确保一个模拟出来的方法在另一个之前被调用。这是一个简化的例子:
function PageManager(page) {
this.page = page;
}
PageManager.prototype.openSettings = function(){
this.page.open();
this.page.setTitle("Settings");
};
在测试中,我可以检查open()
和setTitle()
是否都被调用:
describe("PageManager.openSettings()", function() {
beforeEach(function() {
this.page = jasmine.createSpyObj("MockPage", ["open", "setTitle"]);
this.manager = new PageManager(this.page);
this.manager.openSettings();
});
it("opens page", function() {
expect(this.page.open).toHaveBeenCalledWith();
});
it("sets page title to 'Settings'", function() {
expect(this.page.setTitle).toHaveBeenCalledWith("Settings");
});
});
但是setTitle()
只有在首先调用open()
之后才能起作用。我想先检查是否调用了page.open()
,然后再调用setTitle()
。我想写出像这样的代码:
it("opens page before setting title", function() {
expect(this.page.open).toHaveBeenCalledBefore(this.page.setTitle);
});
但是 Jasmine 似乎没有内置这样的功能。
我可以编写类似以下代码的东西:
beforeEach(function() {
this.page = jasmine.createSpyObj("MockPage", ["open", "setTitle"]);
this.manager = new PageManager(this.page);
// track the order of methods called
this.calls = [];
this.page.open.and.callFake(function() {
this.calls.push("open");
}.bind(this));
this.page.setTitle.and.callFake(function() {
this.calls.push("setTitle");
}.bind(this));
this.manager.openSettings();
});
it("opens page before setting title", function() {
expect(this.calls).toEqual(["open", "setTitle"]);
});
这个方法可以实现,但我想知道是否有更简单的方法来完成。或者有没有一些好的方法来概括这个问题,以便我不需要在其他测试中重复这段代码。
附言:当然,正确的方法是重构代码,消除这种暂时性耦合。但有时可能不可行,例如在与第三方库进行接口时。无论如何……在深入进行进一步的重构之前,我想先对现有的代码进行测试,并尽可能少地修改它。
open
之外,您还可以断言其他内容吗?比如 DOM 节点的更改或其他“全局”数据? - Henrik Andersson