总的来说,我同意戴夫牛顿上面的回答。但是,您应该考虑这种方法的一些极端情况。
使用另一个测试用例对 Dave 的解决方案进行修改:
// production code
var Klass = function() {
this.call_count = 0;
this.called_method();
};
Klass.prototype.called_method = function() {
++this.call_count;
};
// test code
describe("The Klass constructor", function() {
it("should call its prototype's called_method", function() {
spyOn(Klass.prototype, 'called_method');
var k = new Klass();
expect(k.called_method).toHaveBeenCalled();
});
it('some other test', function() {
var k = new Klass();
expect(k.call_count).toEqual(1);
});
});
第二个测试将失败,因为第一个测试中的间谍设置持续跨越测试边界进入第二个方法; called_method 不会增加 call_count,因此 this.call_count 不等于 1。也可能会出现误报的场景 - 测试通过,但不应该。
最重要的是,因为spy仍然存在,创建的Klass实例越多,spy将消耗的内存堆就越大,因为spy会记录对called_method的每次调用。在大多数情况下,这可能不是问题,但您应该意识到这一点,以防万一。
解决这个问题的一个简单方法是确保间谍在使用后被移除。它可能看起来有点难看,但这样的工作:
// test code
describe("The Klass constructor", function() {
it("should call its prototype's called_method", function() {
var spy = jasmine.createSpy('called_method');
var method = Klass.prototype.called_method;
Klass.prototype.called_method = spy;
var k = new Klass();
expect(spy).toHaveBeenCalled();
Klass.prototype.called_method = method;
});
[注意 - 完成一点意见] 更好的解决方案是改变您编写生产代码的方式,使代码更易于测试。通常,对原型进行间谍活动可能是一种需要避免的代码气味。与其在构造函数中实例化依赖项,不如注入它们。不要在构造函数中进行初始化,而是使用适当的 init 方法。