66

Vojta Jina の優れたレポジトリでは、ディレクティブのテストをデモンストレーションしており、モジュール ラッパーの外部でディレクティブ コントローラーを定義しています。ここを参照してください: https://github.com/vojtajina/ng-directive-testing/blob/master/js/tabs.js

それは悪い習慣であり、グローバル名前空間を汚染していませんか?

何か TabsController を呼び出すのが論理的かもしれない別の場所があるとしたら、それは何かを壊すのではないでしょうか?

上記のディレクティブのテストは、https ://github.com/vojtajina/ng-directive-testing/commit/test-controller にあります。

コントローラーをグローバル名前空間に配置せずに、残りのディレクティブとは別にディレクティブ コントローラーをテストすることは可能ですか?

ディレクティブ全体を app.directive(...) 定義内にカプセル化するとよいでしょう。

4

5 に答える 5

75

ディレクティブと一緒にコントローラーを含めることを時々好むので、それをテストする方法が必要です。

まずはディレクティブ

angular.module('myApp', [])
  .directive('myDirective', function() {
    return {
      restrict: 'EA',
      scope: {},
      controller: function ($scope) {
        $scope.isInitialized = true
      },
      template: '<div>{{isInitialized}}</div>'
    }
})

次に、テスト:

describe("myDirective", function() {
  var el, scope, controller;

  beforeEach inject(function($compile, $rootScope) {
    # Instantiate directive.
    # gotacha: Controller and link functions will execute.
    el = angular.element("<my-directive></my-directive>")
    $compile(el)($rootScope.$new())
    $rootScope.$digest()

    # Grab controller instance
    controller = el.controller("myDirective")

    # Grab scope. Depends on type of scope.
    # See angular.element documentation.
    scope = el.isolateScope() || el.scope()
  })

  it("should do something to the scope", function() {
    expect(scope.isInitialized).toBeDefined()
  })
})

インスタンス化されたディレクティブからデータを取得するその他の方法については、 angular.element のドキュメントを参照してください。

ディレクティブをインスタンス化すると、コントローラーとすべてのリンク関数が既に実行されていることを意味するため、テストに影響を与える可能性があることに注意してください。

于 2014-07-15T14:41:22.273 に答える
58

素晴らしい質問です!

したがって、これはコントローラーだけでなく、ディレクティブがそのジョブを実行する必要があるかもしれないが、必ずしもこのコントローラー/サービスを「外部世界」に公開したくないというサービスにも共通する懸念です。

私は、グローバル データは悪であり、避けるべきだと強く信じています。これはディレクティブ コントローラーにも当てはまります。この仮定を使用すると、これらのコントローラーを「ローカルに」定義するためにいくつかの異なるアプローチを取ることができます。その際、コントローラーは単体テストから「簡単に」アクセスできるようにする必要があるため、コントローラーをディレクティブのクロージャーに単純に隠すことはできません。IMO の可能性は次のとおりです。

1) まず、モジュール レベルでディレクティブのコントローラーを簡単に定義できます。例::

angular.module('ui.bootstrap.tabs', [])
  .controller('TabsController', ['$scope', '$element', function($scope, $element) {
    ...
  }])
 .directive('tabs', function() {
  return {
    restrict: 'EA',
    transclude: true,
    scope: {},
    controller: 'TabsController',
    templateUrl: 'template/tabs/tabs.html',
    replace: true
  };
})

これは、 Vojta の作業に基づいたhttps://github.com/angular-ui/bootstrap/blob/master/src/tabs/tabs.jsで使用している単純な手法です。

これは非常に単純な手法ですが、コントローラーは依然としてアプリケーション全体に公開されているため、他のモジュールがそれをオーバーライドする可能性があることに注意してください。この意味で、コントローラーは AngularJS アプリケーションに対してローカルになります (したがって、グローバル ウィンドウ スコープを汚染しません) が、すべての AngularJS モジュールに対してグローバルでもあります。

2)テスト用にクロージャー スコープと特殊ファイルのセットアップを使用します

コントローラー関数を完全に隠したい場合は、コードをクロージャーでラップできます。これは、AngularJS が使用している手法です。たとえば、NgModelControllerを見ると、独自のファイルで「グローバル」関数として定義されている (したがって、テストのために簡単にアクセスできる) ことがわかりますが、ビルド時にファイル全体がクロージャーでラップされていることがわかります。

要約すると、オプション (2) は「より安全」ですが、ビルドには事前に少し設定が必要です。

于 2013-03-09T19:22:59.600 に答える