如何模拟窗口对象?我正在进行firefox扩展,我想使用jasmine进行javascript测试。
在我的javascript中我有
function submit() {
...
var url = window.arguments[0];
...
}
显然,我必须在jasmine中模拟window.arguments [0],因为如果没有从window.openDialog传递任何参数,该对象就不存在
这是我尝试用“with”
来嘲笑它
it("should submit to server", function() {
var localContext = {
"window": {
arguments: ["http://localhost"]
}
}
with(localContext);
但我仍然得到这个错误TypeError:无法读取未定义的属性'0',就像测试运行时一样window.arguments [0]被真实窗口消除了,因为如果我这样做
window.arguments[0]
在测试中,它正确打印出“http:// localhost”。但是当涉及到submit()方法时,它会显示window.argument未定义的错误。
答案 0 :(得分:59)
问题是你只是覆盖了窗口对象的属性。如果你能做到这一点,浏览器也可以做到这一点。因此,模拟每个人都可以访问的全局对象的函数或属性通常不是一个好主意,因为当您尝试访问它们时,您永远无法确定您的更改是否存在。
这让我想到dependency injection。它是使您的代码单元可测试的常见模式,重点是单元。这是什么意思。无论何时创建新对象或访问全局对象,您不仅要测试单元功能,还要测试新创建的或全局对象的功能。要预先添加,请不要在单元中创建新对象,而是将其传递给。通常你会在构造函数中使用它,但是在JavaScript函数中是具有函数体作为构造函数的对象,你也可以将依赖项简单地传递给你的函数。
因此,在您的情况下,该函数取决于全局窗口对象。因此,不要尝试访问全局窗口对象,而是将其作为参数传递给函数。这样做你可以传入生产代码中的window对象和一个带有参数属性的简单JavaScript对象:
function youWannaTest(w){
console.log(w.arguments[0]);
}
在你的扩展程序中调用这样的函数:
youWannaTest(window);
在你的测试中调用这样的函数:
youWannaTest({arguments: ['someValue']});
答案 1 :(得分:3)
我也认为依赖注入是最干净的解决方案。
你的JS:
function submit(_window) {
_window = _window || window
...
var url = _window.arguments[0];
...
}
您的单元测试:
it('works like a dream', function () {
var _window = { arguments: ['url'] }
expect(submit(_window)).toBeTotallyAwesome()
})
答案 2 :(得分:0)
是的,你可以模拟窗口对象。
您需要做的第一件事就是在JS代码中进行一次更改:将窗口替换为 $ window 。
然后,您可以使用以下代码模拟窗口:
var window = {
arguments : ['url']
};
现在在你的spec文件中:在beforeEach block
中$controller('controllerName', {$window : window});