7

$log サービスの機能を拡張するデコレータが Angular にあり、それをテストしたいのですが、これを行う方法がわかりません。ここに私のデコレータのスタブがあります:

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ですか (以下を参照)。

これが私の現在のテストです(モカ/チャイですが、実際には関係ありません):

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);
    }));
  });
});
4

1 に答える 1

6

添付の plunk ( http://j.mp/1p8AcLT ) から、初期バージョンは @jakerella によって提供された (ほとんど) 手つかずのコード (構文のマイナーな調整) です。元の投稿から派生できるのと同じ依存関係を使用しようとしました。注tests.js:12-14:

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

$logご想像のとおり、これはネイティブサービスを完全にオーバーライドし、モック モジュールの構成関数として機能するためMockNativeLog、テストの開始時に提供される実装を使用します。構成関数は FIFO 順に実行されるため、この関数は装飾されたサービスを破壊します。angular.mock.module(fn)$log

解決策の 1 つは、plunk のバージョン 2 からわかるように、その config 関数でデコレータを再適用することです (パーマリンクはいいでしょう、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 が定義するサービスのメソッドを置き換えるため、後の呼び出しが失敗します。このメソッドは によって提供されるスパイではなくなったため、マッチャーは機能しません。debug$logMockNativeLog.debug.should.be.called(1)MockNativeLog.debugchai.spy

代わりに、追加のスパイを作成したことに注意してください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

于 2014-03-18T20:48:05.063 に答える