【问题标题】:How to test angular decorator functionality如何测试角度装饰器功能
【发布时间】:2014-04-24 15:31:33
【问题描述】:

我在 Angular 中有一个装饰器,它将扩展 $log 服务的功能,我想对其进行测试,但我看不到这样做的方法。这是我的装饰器的一个存根:

angular.module('myApp')
  .config(function ($provide) {

    $provide.decorator('$log', ['$delegate', function($delegate) {
      var _debug = $delegate.debug;
      $delegate.debug = function() {
        var args = [].slice.call(arguments);

        // Do some custom stuff

        window.console.info('inside delegated method!');
        _debug.apply(null, args);
      };
      return $delegate
    }]);

  });

请注意,这基本上会覆盖$log.debug() 方法,然后在执行一些自定义操作后调用它。在我的应用程序中这是可行的,我在控制台中看到了 'inside delegated method!' 消息。但在我的测试中,我没有得到那个输出。

如何测试我的装饰器功能?
具体来说,我怎样才能注入我的装饰器,使它真正装饰我的 $log 模拟实现(见下文)?

这是我目前的测试(mocha/chai,但这并不相关):

describe('Log Decorator', function () {
  var MockNativeLog;
  beforeEach(function() {
    MockNativeLog = {
      debug: chai.spy(function() { window.console.log("\nmock debug call\n"); })
    };
  });

  beforeEach(angular.mock.module('myApp'));

  beforeEach(function() {
    angular.mock.module(function ($provide) {
      $provide.value('$log', MockNativeLog);
    });
  });

  describe('The logger', function() {
    it('should go through the delegate', inject(function($log) {
      // this calls my mock (above), but NOT the $log decorator
      // how do I get the decorator to delegate the $log module??
      $log.debug();
      MockNativeLog.debug.should.have.been.called(1);
    }));
  });
});

【问题讨论】:

  • 但是这个想法(如果我没记错的话)是你装饰你的$log,然后你用一个模拟覆盖整个$log。所以很明显,在您的测试中,您将拥有一个带有简单 debug 函数的函数。我想我一路上错过了一些东西。
  • 我为你创建了一个 plunker,我不得不对 angular-mock 进行一些修改,但请查看:plnkr.co/edit/kim2NTNBp0eflOhFVhF3?p=preview
  • 也开始制作plunker。请注意,对angular.module() 的调用需要两个 参数...
  • Plunk 使用 Angular JS 1.2.x,Mocha、Mocha、Chai 和 Chai Spies 的 Angular Mocks:j.mp/1p8AcLT
  • 有趣的想法。谢谢!我会看看,看看我能做什么。另外,@al-the-x,在我的代码中,装饰器在它自己的文件中,所以不需要angular.module() 上的第二个参数,但无论如何都很好!

标签: angularjs testing angularjs-decorator


【解决方案1】:

从附加的 plunk (http://j.mp/1p8AcLT) 来看,初始版本是 @jakerella 提供的(大部分)未修改的代码(对语法进行了细微调整)。我尝试使用可以从原始帖子中获得的相同依赖项。注意tests.js:12-14

angular.mock.module(function ($provide) {
    $provide.value('$log', MockNativeLog);
});

这完全覆盖了原生$log 服务,正如您所料,在测试开始时提供MockNativeLog 实现because angular.mock.module(fn) acts as a config function for the mock module。由于配置函数以 FIFO 顺序执行,因此该函数破坏了已装饰的 $log 服务。

一种解决方案是重新应用装饰器 inside 配置函数,正如您从 plunk 的第 2 版(永久链接会很好,Plunker)中看到的那样,tests.js:12-18

angular.mock.module('myApp', function ($injector, $provide) {
    // This replaces the native $log service with MockNativeLog...
    $provide.value('$log', MockNativeLog);
    // This decorates MockNativeLog, which _replaces_ MockNativeLog.debug...
    $provide.decorator('$log', logDecorator);
});

然而,这还不够。装饰器@jakerella 定义替换$log 服务的debug 方法,导致稍后对MockNativeLog.debug.should.be.called(1) 的调用失败。 MockNativeLog.debug 方法不再是chai.spy 提供的spy,所以matchers 将不起作用。

请注意,我在 tests.js:2-8 中创建了一个额外的间谍:

var MockNativeLog, MockDebug;

beforeEach(function () {
    MockNativeLog = {
        debug: MockDebug = chai.spy(function () {
            window.console.log("\nmock debug call\n");
        })
    };
});

该代码可能更易于阅读:

MockDebug = chai.spy(function () {
    window.console.log("\nmock debug call\n");
});

MockNativeLog = {
    debug: MockDebug
};

这仍然不能代表一个好的测试结果,只是一个健全的检查。在“为什么这不起作用”的问题上敲了几个小时,这让你松了一口气。

请注意,我另外将装饰器函数重构为全局范围,以便我可以在 tests.js 中使用它而无需重新定义它。最好使用$provider.value() 重构为适当的服务,但该任务已留给学生作为练习......或者比我不那么懒惰的人。 :D

【讨论】:

  • 我知道它现在是如何工作的......但是是的,拥有一个全局装饰器功能并不理想。 :) 我会努力将其提取到服务中。
  • 好吧,我可以使用全局对象,但不能使用服务。啊。我不断收到Error: [$injector:unpr] Unknown provider: LogDecorator。无论如何,感谢其他帮助,下次我会看看我能做些什么来作为一项服务。
  • @jakerella 因为这是在配置函数中使用的,所以你可能不得不使用$provider.provider(),实际上,现在我考虑了一下......或者可能只是$provider.constant()
  • 是的,我最终也不得不在其他地方这样做,但那些是为了循环引用。
  • 当然,不用感谢我,如果一个空格不合适,或者如果我看到未突出显示的代码,我会受不了...不过感谢您的回答-这有也困扰了我一段时间。
猜你喜欢
  • 2018-11-19
  • 2021-04-06
  • 2015-04-19
  • 2015-05-25
  • 1970-01-01
  • 1970-01-01
  • 2021-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多