在 Jasmine 中模拟嵌套函数返回 Deferred
Mocking nested function returning Deferred in Jasmine
我正在尝试为使用名为 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()
函数,以便它 return 我在测试中定义的 Json 有效载荷。
read()
方法 return 是一个 $.Deferred
对象。
我尝试了不同的方法(使用 Jasmine 间谍)但没有成功。
我看到有两种方法可以做到这一点:
监视 $.ajax()
并调用 return 自己延迟的假函数
相反:您间接测试了库
mock $.RestClient
s 接口和return你自己的延迟
相反:当不仅需要测试回调时,还需要更多的工作来模拟库。 (您的模拟越复杂,您的测试就越容易出错。)
TL;DR 如果知道请跳过。
但首先让我们看看 RestClient 是如何工作的...它有两个基本对象,一个 Resource 和一个 Verb。 RestClient 实际上是一个 Resource
对象 (1)。 Resource
个对象将 return 另一个 Resource
个对象,当 add()
一个剩余片段 (2) 时。预定义动词 read
将 return 一个 Verb
实例的 call
方法 (3).
- https://github.com/jpillora/jquery.rest/blob/gh-pages/dist/jquery.rest.js#L382
- https://github.com/jpillora/jquery.rest/blob/gh-pages/dist/jquery.rest.js#L241
- https://github.com/jpillora/jquery.rest/blob/gh-pages/dist/jquery.rest.js#L245
从该链的底部到顶部,可以从 call()
方法 (4) 访问 request
方法。如果未明确覆盖,则默认为 $.ajax()
。 (5)
- https://github.com/jpillora/jquery.rest/blob/gh-pages/dist/jquery.rest.js#L174
- https://github.com/jpillora/jquery.rest/blob/gh-pages/dist/jquery.rest.js#L66
如果没有进行不同的配置,对 read()
的调用将导致对 $.ajax()
的调用,return 承诺。
因此,在执行新的 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();
});
});
伪造的是 return 延期,而不是承诺,但在这种情况下没关系,因为它具有相同的接口,并且 nothing/no 除了我们之外,应该拒绝或解决这里的延期.
变体 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
的模拟需要比我所做的更多的工作,使用上面的代码这是不可能的。
我正在尝试为使用名为 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()
函数,以便它 return 我在测试中定义的 Json 有效载荷。
read()
方法 return 是一个 $.Deferred
对象。
我尝试了不同的方法(使用 Jasmine 间谍)但没有成功。
我看到有两种方法可以做到这一点:
监视
$.ajax()
并调用 return 自己延迟的假函数相反:您间接测试了库
mock
$.RestClient
s 接口和return你自己的延迟相反:当不仅需要测试回调时,还需要更多的工作来模拟库。 (您的模拟越复杂,您的测试就越容易出错。)
TL;DR 如果知道请跳过。
但首先让我们看看 RestClient 是如何工作的...它有两个基本对象,一个 Resource 和一个 Verb。 RestClient 实际上是一个 Resource
对象 (1)。 Resource
个对象将 return 另一个 Resource
个对象,当 add()
一个剩余片段 (2) 时。预定义动词 read
将 return 一个 Verb
实例的 call
方法 (3).
- https://github.com/jpillora/jquery.rest/blob/gh-pages/dist/jquery.rest.js#L382
- https://github.com/jpillora/jquery.rest/blob/gh-pages/dist/jquery.rest.js#L241
- https://github.com/jpillora/jquery.rest/blob/gh-pages/dist/jquery.rest.js#L245
从该链的底部到顶部,可以从 call()
方法 (4) 访问 request
方法。如果未明确覆盖,则默认为 $.ajax()
。 (5)
- https://github.com/jpillora/jquery.rest/blob/gh-pages/dist/jquery.rest.js#L174
- https://github.com/jpillora/jquery.rest/blob/gh-pages/dist/jquery.rest.js#L66
如果没有进行不同的配置,对 read()
的调用将导致对 $.ajax()
的调用,return 承诺。
因此,在执行新的 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();
});
});
伪造的是 return 延期,而不是承诺,但在这种情况下没关系,因为它具有相同的接口,并且 nothing/no 除了我们之外,应该拒绝或解决这里的延期.
变体 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
的模拟需要比我所做的更多的工作,使用上面的代码这是不可能的。