48

だから私は別の質問を見ました:基本的に私の問題であるディレクティブUTで必要なディレクティブコントローラーをモックする方法ですが、このスレッドへの答えは「デザインを変更する」だったようです。これを行う方法がないことを確認したかったのです。子ディレクティブで使用されるコントローラーを宣言するディレクティブがあります。私は現在、children ディレクティブのジャスミン テストを作成しようとしていますが、コントローラーに依存しているため、テストでコンパイルすることはできません。これは次のようになります。

addressModule.directive('address', ['$http', function($http){
        return {
            replace: false,
            restrict: 'A',
            scope: {
                config: '='
            },
            template:   '<div id="addressContainer">' +
                            '<div ng-if="!showAddressSelectionPage" basic-address config="config"/>' +
                            '<div ng-if="showAddressSelectionPage" address-selector addresses="standardizedAddresses"/>' +
                        '</div>',
            controller: function($scope)
            {
                this.showAddressInput = function(){
                    $scope.showAddressSelectionPage = false;
                };

                this.showAddressSelection = function(){
                    $scope.getStandardizedAddresses();
                };

                this.finish = function(){
                    $scope.finishAddress();
                };
            },
            link: function(scope, element, attrs) {
              ...
            }
       }
}])

子ディレクティブ:

addressModule.directive('basicAddress360', ['translationService', function(translationService){
        return {
            replace: true,
            restrict: 'A',
            scope: {
                config: '='
            },
            template:
                '...',
            require: "^address360",
            link: function(scope, element, attrs, addressController){
            ...
            }
       }
}])

ジャスミンテスト:

it("should do something", inject(function($compile, $rootScope){
            parentHtml = '<div address/>';
            subDirectiveHtml = '<div basic-address>';

            parentElement = $compile(parentHtml)(rootScope);
            parentScope = parentElement.scope();
            directiveElement = $compile(subDirectiveHtml)(parentScope);
            directiveScope = directiveElement.scope();
            $rootScope.$digest();
}));

サブディレクティブをジャスミンでテストする方法はありませんか?もしそうなら、何が欠けていますか? コントローラー関数なしでディレクティブ自体をテストできたとしても、私は幸せです。

4

3 に答える 3

57

Michael Benfordの (素晴らしい) 回答のフォーク。

テストでコントローラー/ディレクティブを完全に分離したい場合は、少し異なるアプローチが必要になります。

3) 必要な親コントローラーを完全にモックする

コントローラーをディレクティブに関連付けると、コントローラーのインスタンスが要素のデータ ストアに格納されます。キー値の命名規則は'$' + ディレクティブの名前 + 'Controller'です。Angular が必要なコントローラーを解決しようとするときはいつでも、この規則を使用してデータ階層をトラバースし、必要なコントローラーを見つけます。これは、モック化されたコントローラー インスタンスを親要素に挿入することで簡単に操作できます。

it('ensures callFoo does whatever it is supposed to', function() {

    // Arrange

    var fooCtrl = {
      add: function() { return 123; }
    };

    spyOn(fooCtrl, 'add').andCallThrough();

    var element = angular.element('<div><bar></bar></div>');
    element.data('$fooController', fooCtrl);

    $compile(element)($scope);

    var barScope = element.find('bar').scope();

    // Act

    barScope.callFoo(1, 2);

    // Assert

    expect(barScope.sum).toBe(123);
    expect(fooCtrl.add).toHaveBeenCalled();
});

ワーキングプランカー。

4) セパレートリンク方式

私の意見では、最良のアプローチはリンク メソッドを分離することです。これまでのすべてのアプローチは、実際にはテストが多すぎるため、ここで提供されている単純な例よりも状況が少し複雑になると、セットアップが必要になりすぎます。

Angular は、この関心の分離を完全にサポートしています。

// Register link function

app.factory('barLinkFn', function() {
  return function(scope, element, attrs, foo) {
    scope.callFoo = function(x, y) {
      scope.sum = foo.add(x, y);
    };
  };
});

// Register directive

app.directive('bar', function(barLinkFn) {
  return {
    restrict: 'E',
    require: '^foo',
    link: barLinkFn
  };
});

そして、beforeEachを変更してリンク関数を含めることで ... :

inject(function(_barLinkFn_) {
  barLinkFn = _barLinkFn_;
});

... 我々はできる:

it('ensures callFoo does whatever it is supposed to', function() {

  // Arrange

  var fooCtrl = {
    add: function() { return 321; }
  };

  spyOn(fooCtrl, 'add').andCallThrough();

  barLinkFn($scope, $element, $attrs, fooCtrl);

  // Act

  $scope.callFoo(1, 2);

  // Assert

  expect($scope.sum).toBe(321);
  expect(fooCtrl.add).toHaveBeenCalled();

});

ワーキングプランカー。

このようにして、関係するものだけをテストし、必要に応じて同じアプローチを使用してコンパイル機能を分離できます。

于 2013-11-13T10:20:20.787 に答える