javascript 是否可以为 qUnit 测试模拟 window.location 对象?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11891502/
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
Is it possible to mock the window.location object for a qUnit test?
提问by jbabey
Let's say I have a utility function that, for simplicity's sake (the real thing is complicated and irrelevant), returns the current window's querystring.
假设我有一个实用函数,为了简单起见(实际情况很复杂且无关紧要),它返回当前窗口的查询字符串。
var someUtilityFunction = () {
return window.location.search.substring(1);
};
Now I want to unit test this function in qUnit (not sure if the testing harness is relevant or not):
现在我想在 qUnit 中对这个函数进行单元测试(不确定测试工具是否相关):
test('#1 someUtilityFunction works', function () {
// setup
var oldQS = window.location.search;
window.location.search = '?key1=value1&key2=value2&key3=value3';
var expectedOutput = 'key1=value1&key2=value2&key3=value3';
// test
equals(someUtilityFunction(),
expectedOutput,
'someUtilityFunction works as expected.');
// teardown
window.location.search = oldQS;
});
The problem here is that setting the window.location.search
to a different querystring is causing the page to reload, essentially entering an infinite request loop. Is there any way to mock out the window.location object withoutmaking any changes to the someUtilityFunction
function?
这里的问题是将 设置window.location.search
为不同的查询字符串会导致页面重新加载,实质上进入了无限请求循环。有没有办法模拟 window.location 对象而不对someUtilityFunction
函数进行任何更改?
回答by Torsten Walter
We run into the same problem a few days ago. Mainly there are 2 approaches:
几天前我们遇到了同样的问题。主要有2种做法:
Rewrite your code
重写你的代码
This might not be the best (if any) solution, but consider passing the window
object to your function to make mocking easier. Even better, use a closure and encapsulate your code. This has a few more advantages:
这可能不是最好的(如果有的话)解决方案,但请考虑将window
对象传递给您的函数以使模拟更容易。更好的是,使用闭包并封装您的代码。这还有几个优点:
- You can shadow global vars
- You can use private local vars
- You can avoid naming collisions
- The shadowing makes mocking really easy, just pass in something else
- 您可以隐藏全局变量
- 您可以使用私有本地变量
- 您可以避免命名冲突
- 阴影使模拟变得非常容易,只需传入其他内容即可
Wrap your code
包装你的代码
You can wrap all your code inside a function which mocks the window object into a local variable. You have basically two possibilities there as well:
您可以将所有代码包装在一个函数中,该函数将窗口对象模拟为局部变量。您基本上也有两种可能性:
Suppose this is the mock:
假设这是模拟:
var customWindow = {
location: {
search: "",
hash: ""
}
};
Use a closure
使用闭包
var someUtilityFunction;
(function(window) {
// window is now shadowed by your local variable
someUtilityFunction = () {
return window.location.search.substring(1);
};
})(customWindow);
This shadows the global window
with a local window
.
这会window
用本地window
.
Use the with
statement
使用with
语句
Although I am usually strongly against with, it could really solve a lot of problems here. Since it basically remaps your scope, you can very easily mock your environment.
虽然我通常强烈反对with,但它在这里确实可以解决很多问题。由于它基本上重新映射了您的范围,因此您可以非常轻松地模拟您的环境。
// first some more preparation for our mock
customWindow.window = customWindow;
with(customWindow) {
// this still creates the var in the global scope
var someUtilityFunction = () {
// window is a property of customWindow
return window.location.search.substring(1);
};
// since customWindow is our scope now
// this will work also
someUtilityFunction = () {
// location is a property of customWindow too
return location.search.substring(1);
};
}
By the way: I don't know if the search
property suffers from the same symptoms as the hash
property - namely sometimes including the question mark and sometimes not. But you might want to consider using
顺便说一句:我不知道该search
物业是否与该物业有相同的症状hash
- 即有时包括问号,有时不包括。但你可能想考虑使用
window.location.search.replace(/^\?/, "");
instead of
代替
window.location.substr(1);
回答by Sam Schneider
I've had some success using window.history.pushState
. See this StackOverflow answer. For each unit test, I call a function setQueryString('var=something')
which I then implement like this:
我在使用window.history.pushState
. 请参阅此 StackOverflow 答案。对于每个单元测试,我调用一个函数setQueryString('var=something')
,然后像这样实现:
function setQueryString(queryString) {
window.history.pushState({}, '', '?' + queryString);
}
You'll need to clear the query string with the afterEach
method of QUnit.module, otherwise you're query string will be set to the value of the final test, and you'll get weird results.
您需要使用afterEach
QUnit.module的方法清除查询字符串,否则您的查询字符串将被设置为最终测试的值,并且您会得到奇怪的结果。