工厂方法引用混淆,以及编码指南
Factory method reference confusion, and guideline to code it
我有以下 angular 服务。
(function () {
"use strict";
angular.module("theModule")
.factory("theService", theServiceFactory);
function theServiceFactory() {
return {
theFn: theFn,
theFailureFn: theFailureFn,
theSuccessFn: theSuccessFn
};
function theFn() {
angular.noop();
}
function theFailureFn() {
theFn();
}
function theSuccessFn() {
this.theFn();
}
}
}());
函数是单独定义的,它们的引用被分配给工厂返回的对象。
我有以下 jasmine 测试用例。
describe("The Service Test Specifications", function () {
var theService;
beforeEach(module('theModule'));
beforeEach(inject(function(_theService_) {
theService = _theService_;
}));
it("should call 'theFn' from 'theFailureFn'", function () {
spyOn(theService, "theFn");
theService.theFailureFn();
expect(theService.theFn).toHaveBeenCalled();
});
it("should call 'theFn' from 'theSuccessFn'", function () {
spyOn(theService, "theFn");
theService.theSuccessFn();
expect(theService.theFn).toHaveBeenCalled();
});
});
测试用例 should call 'theFn' from 'theFailure'
失败,而 should call 'theFn' from 'theSuccess'
通过。
从源代码看来 object's theFn
指的是 function theFn
但实际上不是。它导致第一个测试用例失败。 (Q1) object's theFn
在哪个阶段分配了不同的引用?
第二个测试用例通过,因为 theFn
在 theSuccess
中用 this
调用。但是在那种情况下使用 this
是违反严格模式的。我喜欢并关注 John Papa's style guide,所以我创建了 factory
并定义了它下面的所有函数。 (Q2) 怎样写这样的函数比较好?
(Q3)如果theFailure
写对了,在测试用例中有没有办法检测调用了function theFn
?
它实际上是从 theFailureFn()
调用 theFn()
,而不是从 sucesssFn()
调用 theFn()
。和你的测试结果相反。
从这里可以看出,
http://plnkr.co/edit/Tp5FtsL8DAjkcPO0m0ZV?p=preview
console.log('theService.theFn BEFORE spyOn', theService.theFn);
spyOn(theService, "theFn");
console.log('theService.theFn AFTER spyOn', theService.theFn);
结果
theService.theFn BEFORE spyOn theFn()
theService.theFn AFTER spyOn j$.createSpy.spy()
您的 Jasmine spyOn(theService, "theFn");
正在设置服务实例 this.theFn
,并且您的测试正在检查 this.theFn
是否被调用。请记住 theService
是哈希,而不是函数。
正如您从该行的输出中看到的那样;
console.log('caller theFailureFn', this, theFn, this.theFn)
//OUTPUT
caller theFailureFn Object {} theFn() j$.createSpy.spy()
theFn
和this.theFn
是很不一样的。 theFn
是一个对象 属性 值,this.theFn
是对象 Hash 的一个实例。
为了回答你的问题,
(Q1) 在什么阶段将不同的引用分配给对象的theFn
theFn
已按预期分配。 spyOn
让你的情况有所不同。
(Q2)写这样的函数用什么方法比较好?
要测试函数调用对象的函数,它应该 return 函数,而不是散列。
(Q3)如果theFailure写对了,有没有办法在test case中检测调用了函数theFn?
与Q2相同的答案。
不要在 .factory()
中使用 this
。工厂只是作为函数执行,它只是 return 明确指定为 return 对象的内容。 Angular 使用 .service()
作为构造函数,使用 new
运算符执行,这就是您将使用 this
.
的地方
这意味着你的 theFailureFn()
写对了。
至于Q3,可能因为spyOn的实现方式而失败。
编辑:
如我所料,它是 spyOn()
.
的实现
spyOn 包装了函数,但在您的工厂中您仍然引用原始函数。尝试使用 expect(this.theFn).toHaveBeenCalled();
我有以下 angular 服务。
(function () {
"use strict";
angular.module("theModule")
.factory("theService", theServiceFactory);
function theServiceFactory() {
return {
theFn: theFn,
theFailureFn: theFailureFn,
theSuccessFn: theSuccessFn
};
function theFn() {
angular.noop();
}
function theFailureFn() {
theFn();
}
function theSuccessFn() {
this.theFn();
}
}
}());
函数是单独定义的,它们的引用被分配给工厂返回的对象。
我有以下 jasmine 测试用例。
describe("The Service Test Specifications", function () {
var theService;
beforeEach(module('theModule'));
beforeEach(inject(function(_theService_) {
theService = _theService_;
}));
it("should call 'theFn' from 'theFailureFn'", function () {
spyOn(theService, "theFn");
theService.theFailureFn();
expect(theService.theFn).toHaveBeenCalled();
});
it("should call 'theFn' from 'theSuccessFn'", function () {
spyOn(theService, "theFn");
theService.theSuccessFn();
expect(theService.theFn).toHaveBeenCalled();
});
});
测试用例 should call 'theFn' from 'theFailure'
失败,而 should call 'theFn' from 'theSuccess'
通过。
从源代码看来 object's theFn
指的是 function theFn
但实际上不是。它导致第一个测试用例失败。 (Q1) object's theFn
在哪个阶段分配了不同的引用?
第二个测试用例通过,因为 theFn
在 theSuccess
中用 this
调用。但是在那种情况下使用 this
是违反严格模式的。我喜欢并关注 John Papa's style guide,所以我创建了 factory
并定义了它下面的所有函数。 (Q2) 怎样写这样的函数比较好?
(Q3)如果theFailure
写对了,在测试用例中有没有办法检测调用了function theFn
?
它实际上是从 theFailureFn()
调用 theFn()
,而不是从 sucesssFn()
调用 theFn()
。和你的测试结果相反。
从这里可以看出,
http://plnkr.co/edit/Tp5FtsL8DAjkcPO0m0ZV?p=preview
console.log('theService.theFn BEFORE spyOn', theService.theFn);
spyOn(theService, "theFn");
console.log('theService.theFn AFTER spyOn', theService.theFn);
结果
theService.theFn BEFORE spyOn theFn()
theService.theFn AFTER spyOn j$.createSpy.spy()
您的 Jasmine spyOn(theService, "theFn");
正在设置服务实例 this.theFn
,并且您的测试正在检查 this.theFn
是否被调用。请记住 theService
是哈希,而不是函数。
正如您从该行的输出中看到的那样;
console.log('caller theFailureFn', this, theFn, this.theFn)
//OUTPUT
caller theFailureFn Object {} theFn() j$.createSpy.spy()
theFn
和this.theFn
是很不一样的。 theFn
是一个对象 属性 值,this.theFn
是对象 Hash 的一个实例。
为了回答你的问题,
(Q1) 在什么阶段将不同的引用分配给对象的theFn
theFn
已按预期分配。 spyOn
让你的情况有所不同。
(Q2)写这样的函数用什么方法比较好?
要测试函数调用对象的函数,它应该 return 函数,而不是散列。
(Q3)如果theFailure写对了,有没有办法在test case中检测调用了函数theFn? 与Q2相同的答案。
不要在 .factory()
中使用 this
。工厂只是作为函数执行,它只是 return 明确指定为 return 对象的内容。 Angular 使用 .service()
作为构造函数,使用 new
运算符执行,这就是您将使用 this
.
这意味着你的 theFailureFn()
写对了。
至于Q3,可能因为spyOn的实现方式而失败。
编辑:
如我所料,它是 spyOn()
.
spyOn 包装了函数,但在您的工厂中您仍然引用原始函数。尝试使用 expect(this.theFn).toHaveBeenCalled();