Javascript Jasmine - 监视构造函数中的方法调用
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/8733978/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Jasmine - Spying on a method call within a constructor
提问by Levi McCallum
I want to test whether the following method is called with in my Javascript object constructor. From what I have seen in the Jasmine documentation, I can spy on a constructor method and I can spy on methods after an object has been instantiated, but I can't seem to be able to spy on a method before the object is constructed.
我想测试是否在我的 Javascript 对象构造函数中调用了以下方法。从我在 Jasmine 文档中看到的内容来看,我可以窥探构造函数方法,并且可以在实例化对象后窥探方法,但是在构造对象之前,我似乎无法窥探方法。
The object:
物体:
Klass = function() {
this.called_method();
};
Klass.prototype.called_method = function() {
//method to be called in the constructor.
}
I want to do something like this in the spec:
我想在规范中做这样的事情:
it('should spy on a method call within the constructor', function() {
spyOn(window, 'Klass');
var obj = new Klass();
expect(window.Klass.called_method).toHaveBeenCalled();
});
回答by Dave Newton
Spy directly on the prototype method:
直接窥探原型方法:
describe("The Klass constructor", function() {
it("should call its prototype's called_method", function() {
spyOn(Klass.prototype, 'called_method'); //.andCallThrough();
var k = new Klass();
expect(Klass.prototype.called_method).toHaveBeenCalled();
});
});
回答by alecmce
Broadly, I agree with Dave Newton's answer above. However, there are some edge-cases to this approach that you should consider.
总的来说,我同意上面戴夫牛顿的回答。但是,您应该考虑这种方法的一些边缘情况。
Take a variation to Dave's solution, with another test-case:
使用另一个测试用例对 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);
});
});
The second test will fail because the spy setup in the first test persists across the test boundaries into the second method; called_method doesn't increment call_count, so this.call_count does not equal 1. It's also possible to come up with scenarios with false positives - tests that pass, that shouldn't.
第二个测试将失败,因为第一个测试中的间谍设置跨测试边界持续到第二个方法中;Called_method 不会增加 call_count,因此 this.call_count 不等于 1。也可能会出现误报的情况 - 测试通过,但不应该。
On top of this, because the spy remains, the more Klass instances that are created, the bigger the memory heap the spy will consume, because the spy will record each call to called_method. This probably isn't a problem in most circumstances, but you should be aware of it, just in case.
最重要的是,因为 spy 仍然存在,所以创建的 Klass 实例越多,spy 消耗的内存堆就越大,因为 spy 会记录对 called_method 的每次调用。在大多数情况下,这可能不是问题,但您应该意识到这一点,以防万一。
A simple solution to this problem would be to make sure that the spy is removed after it has been used. It can look a bit ugly, but something like this works:
这个问题的一个简单解决方案是确保间谍在使用后被移除。它看起来有点难看,但像这样有效:
// 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;
});
[NOTE - a little opinion to finish] A better solution would be to change the way you write production code to make the code easier to test. As a rule, spying on prototypes is probably a code-smell to be avoided. Instead of instantiating dependencies in the constructor, inject them. Instead of doing initialization in the constructor, defer to an appropriate init method.
[注意 - 需要完成的一点意见] 更好的解决方案是更改编写生产代码的方式,使代码更易于测试。通常,监视原型可能是一种需要避免的代码味道。不是在构造函数中实例化依赖项,而是注入它们。不要在构造函数中进行初始化,而是使用适当的 init 方法。