工厂方法引用混淆,以及编码指南

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 在哪个阶段分配了不同的引用?

第二个测试用例通过,因为 theFntheSuccess 中用 this 调用。但是在那种情况下使用 this 是违反严格模式的。我喜欢并关注 John Papa's style guide,所以我创建了 factory 并定义了它下面的所有函数。 (Q2) 怎样写这样的函数比较好?

(Q3)如果theFailure写对了,在测试用例中有没有办法检测调用了function theFn


Plunkr:http://plnkr.co/edit/PsQTZQlIgWI3OTMaYi7n

它实际上是从 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()

theFnthis.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();