如何用 Jasmine 模拟 jQuery
How to mock jQuery with Jasmine
我想做什么: 我们正在为大量使用 jQuery 的现有 Javascript 代码库编写一些测试。对于测试,我们不希望有实际的 HTML 元素(HTML 固定装置)。如果我们有一个不做任何 HTML 相关的 jQuery 模拟对象,我们会更喜欢它。
我的出发点: 我在这里找到的最有前途的方法:
http://eclipsesource.com/blogs/2014/03/27/mocks-in-jasmine-tests/
这将创建一个辅助方法,该方法通过遍历对象的函数并为每个函数创建一个间谍来创建模拟:
window.mock = function (constr, name) {
var keys = [];
for (var key in constr.prototype)
keys.push( key );
return keys.length > 0 ? jasmine.createSpyObj( name || "mock", keys ) : {};
};
然后,如果我没理解错的话,他是这样使用的(改编自他的博客 post 的例子):
var el = mock($);
el('.some-not-existing-class').css('background', 'red');
expect(el.css).toHaveBeenCalledWith('background', 'red');
但是,这不起作用,因为 el
是 object
而不是 function
。
我解决这个问题的方法: 我重构了他的 mock
函数以解决 constr
是 function
的情况:
mock (constr, name) {
var keys = [];
for (var key in constr.prototype)
keys.push(key);
var result = keys.length > 0 ? jasmine.createSpyObj(name || "mock", keys) : {};
// make sure that if constr is a function (like in the case of jQuery), the mock is too
if (typeof constr === 'function') {
var result2 = result;
result = jasmine.createSpy(name || 'mock-fn');
for (var key in result2)
result[key] = result2[key];
}
return result;
}
但是,测试中的第二行抛出 Cannot read property css of undefined
错误:
var el = mock($);
el('.some-not-existing-class').css('background', 'red');
expect(el.css).toHaveBeenCalledWith('background', 'red');
其他想法:我也尝试将间谍对象合并到jQuery中,但这也没有帮助。
有什么想法吗?我希望我们不是唯一没有 HTML 固定装置的人。
您可以使用 sinon.js stubs,而不是滚动您自己的辅助方法。
stub = sinon.stub(jQuery.fn, 'css');
// invoke code which calls the stubbed function
expect(stub.calledWith({ 'background': 'red' })).toBe(true);
stub.restore();
找到了。当我的 mock
函数版本设置为 return 调用 jQuery 函数时 jQuery 对象,测试有效:
mock (constr, name) {
var keys = [];
for (var key in constr.prototype)
keys.push(key);
var result = keys.length > 0 ? jasmine.createSpyObj(name || "mock", keys) : {};
// make sure that if constr is a function (like in the case of jQuery), the mock is too
if (typeof constr === 'function') {
var result2 = result;
result = jasmine.createSpy(name || 'mock-fn');
result.and.returnValue(result);
for (var key in result2)
result[key] = result2[key];
}
return result;
}
我想做什么: 我们正在为大量使用 jQuery 的现有 Javascript 代码库编写一些测试。对于测试,我们不希望有实际的 HTML 元素(HTML 固定装置)。如果我们有一个不做任何 HTML 相关的 jQuery 模拟对象,我们会更喜欢它。
我的出发点: 我在这里找到的最有前途的方法:
http://eclipsesource.com/blogs/2014/03/27/mocks-in-jasmine-tests/
这将创建一个辅助方法,该方法通过遍历对象的函数并为每个函数创建一个间谍来创建模拟:
window.mock = function (constr, name) {
var keys = [];
for (var key in constr.prototype)
keys.push( key );
return keys.length > 0 ? jasmine.createSpyObj( name || "mock", keys ) : {};
};
然后,如果我没理解错的话,他是这样使用的(改编自他的博客 post 的例子):
var el = mock($);
el('.some-not-existing-class').css('background', 'red');
expect(el.css).toHaveBeenCalledWith('background', 'red');
但是,这不起作用,因为 el
是 object
而不是 function
。
我解决这个问题的方法: 我重构了他的 mock
函数以解决 constr
是 function
的情况:
mock (constr, name) {
var keys = [];
for (var key in constr.prototype)
keys.push(key);
var result = keys.length > 0 ? jasmine.createSpyObj(name || "mock", keys) : {};
// make sure that if constr is a function (like in the case of jQuery), the mock is too
if (typeof constr === 'function') {
var result2 = result;
result = jasmine.createSpy(name || 'mock-fn');
for (var key in result2)
result[key] = result2[key];
}
return result;
}
但是,测试中的第二行抛出 Cannot read property css of undefined
错误:
var el = mock($);
el('.some-not-existing-class').css('background', 'red');
expect(el.css).toHaveBeenCalledWith('background', 'red');
其他想法:我也尝试将间谍对象合并到jQuery中,但这也没有帮助。
有什么想法吗?我希望我们不是唯一没有 HTML 固定装置的人。
您可以使用 sinon.js stubs,而不是滚动您自己的辅助方法。
stub = sinon.stub(jQuery.fn, 'css');
// invoke code which calls the stubbed function
expect(stub.calledWith({ 'background': 'red' })).toBe(true);
stub.restore();
找到了。当我的 mock
函数版本设置为 return 调用 jQuery 函数时 jQuery 对象,测试有效:
mock (constr, name) {
var keys = [];
for (var key in constr.prototype)
keys.push(key);
var result = keys.length > 0 ? jasmine.createSpyObj(name || "mock", keys) : {};
// make sure that if constr is a function (like in the case of jQuery), the mock is too
if (typeof constr === 'function') {
var result2 = result;
result = jasmine.createSpy(name || 'mock-fn');
result.and.returnValue(result);
for (var key in result2)
result[key] = result2[key];
}
return result;
}