我正在尝试为使用名为jquery.rest的jQuery ajax包装器库的模块编写Jasmine测试
此模块正在测试中:
var module = function() {
function getData(callback) {
IP.read().done(function (data) {
console.log("done");
callback(data);
});
}
return {
getData: getData
}
}();
client
和IP
变量在不同的文件中声明,如下所示:
var client = new $.RestClient('/rest/api/');
var IP = client.add('ip');
我想模拟read()
函数,以便它返回我在测试中定义的Json有效负载。
read()
方法返回$.Deferred
个对象。
我尝试了不同的方法(使用Jasmine间谍)但没有成功。
答案 0 :(得分:1)
我认为有两种方法可以做到这一点:
spy $.ajax()
并调用返回您自己的延迟
Contra:你间接测试了库
模拟$.RestClient
界面并返回您自己的延迟
Contra:当不仅需要测试回调时,还需要更多模拟库。 (你的模拟越复杂,你的测试就越容易出错。)
TL; DR 如果已知,请跳过此。
但首先让我们看一下RestClient的工作原理......它有两个基本对象,一个是资源和一个动词。 RestClient实际上是一个Resource
对象(1)。当Resource
休息片段(2)时,Resource
个对象将返回另一个add()
对象。预定义的动词read
将返回Verb
实例的call
方法(3)。
从该链的底部到顶部,可以从request
方法(4)访问call()
方法。如果未明确覆盖,则默认为$.ajax()
。 (5)
如果配置不同,拨打read()
会调用$.ajax()
,并返回承诺。
因此,在进行新的new $.RestClient().add("...").add("...").read()
时,您将获得$.ajax()
所获得的内容。
变式1:
describe("getData()", function(){
// Handle to ajax()' deferred, scoped to the
// describe so the fake ajax() and the it()
// have access to it
var def,
underTest;
beforeEach(function(){
// Mock $.ajax (or what a Verb calls in the end)
// assign "def" with a deferred and return it,
// the test can then resolve() or reject() it
spyOn($, "ajax").and.callFake(function(opts) {
def = $.Deferred();
return def;
});
// This is under test
underTest = new UnderTest();
});
afterEach(function(){
// Ensure a missing call of ajax() will fail the test
def = null;
});
it("should call callback on successful read", function() {
var callback = jasmine.createSpy("callback");
// Indirectly call ajax() which will create def
underTest.getData(callback);
// Resolve the deferred to succeed the response
def.resolve({a: 1});
expect(callback).toHaveBeenCalledWith({a: 1});
});
it("should not call callback on failed read", function(){
var callback = jasmine.createSpy("callback");
underTest.getData(callback);
def.reject();
expect(callback).not.toHaveBeenCalled();
});
});
假货正在退货,而不是承诺,但在这种情况下它没有问题,因为它有相同的界面,除了我们之外,没有人/没有人应该拒绝或解决延期。
变体2:
describe("getData()", function(){
// Store original reference
var origRestClient,
// See first code block
def,
underTest;
// Mock thr Resouce object
function MockResource() { }
// Simplify the behaviour of this mock,
// return another Mock resource
MockResource.prototype.add = function() {
return new MockResource();
};
// What Verb.call() would do, but directly
// return a deferred
MockResource.prototype.read = function() {
def = $.Deferred();
return def;
};
beforeEach(function(){
// Replace RestClient
origRestClient = $.RestClient;
$.RestClient = MockResource;
underTest = new UnderTest();
});
afterEach(function(){
// Restore RestClient
$.RestClient = origRestClient;
def = null;
});
it("should call callback on successful read", function() {
var callback = jasmine.createSpy("callback");
underTest.getData(callback);
def.resolve({a: 1});
expect(callback).toHaveBeenCalledWith({a: 1});
});
it("should not call callback on failed read", function(){
var callback = jasmine.createSpy("callback");
underTest.getData(callback);
def.reject();
expect(callback).not.toHaveBeenCalled();
});
});
如果您想测试路径并请求数据,那么Resouce
的模拟需要的工作量比我所做的要多,使用上面的代码是不可能的。