Jasmine:在带有函数引用的 spyOn 之后调用的真实函数

Jasmine: Real function being called after spyOn with function reference

我有一个 angular 服务。在这个服务中,我有一个带有函数的对象,它引用了服务上的另一个函数。 (下面的代码)

我想使用 Jasmine (1.3) 来监视我的服务函数,以验证当对象的函数被调用时,它实际上调用了真正的函数。

我的问题:调用spyOn后,真正的函数还在调用

FooService.js

angular.module('foo').service("FooService", function() {
     var self = this;

     this.fooFunction = function() {
         console.log("Foo function is being called");
     }

     this.bar = {
         barFunction : self.fooFunction
     }
});

FooService-spec.js

describe("Testing FooService", function() {
     var service;

     beforeEach(inject(function(_FooService_) {
         service = _FooService_;
     }));

     describe("Test bar object", function() {
        it("should call fooFunction when bar.barFunction is called", function() {
             spyOn(service, "fooFunction");
             service.bar.barFunction();
             expect(service.fooFunction).toHaveBeenCalled();
         });
     });
 });

我发现如果我将 FooServce.js 更改为以下内容,这一切都有效:

FooService - 工作

angular.module('foo').service("FooService", function() {
     var self = this;

     this.fooFunction = function() {
         console.log("Real function is being called");
     }

     this.bar = {
         barFunction : function() {
             return self.fooFunction();
         }
     }
 });

第一个例子JavaScript/Angular/Jasmine我哪里没看懂?

spyOn 通过将对象 属性 的值替换为不同的值来进行操作。当您执行 spyOn(service, "fooFunction"); 时,您正在执行类似

的操作
var realFunc = service.fooFunction;
service.fooFunction = function() {
    doSpyStuff();
    return realFunc.apply(this, arguments);
}

请注意,这不会修改值 service.fooFunction。它实际上修改了 service —— 也就是说, service 的一个属性现在是一个完全不同的函数。此替换只会影响 servicefooFunction 属性。如果您没有访问 service 的 属性,那么您肯定不会调用间谍功能。

所以让我们将这些知识应用到您的案例中。在您的测试中,您正在访问 service.bar 的 属性。虽然 service.bar.barFunctionservice.fooFunction 最初是相同的值,但 service 已将其 fooFunction 属性 替换为间谍,而(非常重要的)service.bar 的任何属性都没有被 spyOn 改变。当你调用 service.bar.barFunction() 时,你直接调用了真正的函数,与 servicefooFunction 属性.

上的间谍没有任何联系

相比之下,当您将 barFunction: function() { return self.fooFunction(); } 作为匿名函数执行时,您实际上 访问 service 上的间谍 属性 值,因为这里self恰好是service,所以self.fooFunctionservice.fooFunction,也就是持有间谍替换值的属性。