19

いくつかのチュートリアルと基本的な例を実行しましたが、コントローラーの単体テストを作成するのに苦労しています。コントローラーをインスタンス化し、Angularにオブジェクトを注入させ、コントローラー$rootScopeの新しいscopeオブジェクトを作成するために使用されるコードスニペットを見てきました。しかし、なぜかわかりませんかctrl.$scope未定義です:

 describe('EmployeeCtrl', function () {
    var scope, ctrl, $httpBackend;

    beforeEach(inject(function (_$httpBackend_, $rootScope, $controller, $filter) {
        $httpBackend = _$httpBackend_;       

        scope = $rootScope.$new();
        ctrl = $controller('EmployeeCtrl', { $scope: scope});
        expect(ctrl).not.toBeUndefined();
        expect(scope).not.toBeUndefined();   //<-- PASS!      
        expect(ctrl.$scope).not.toBeUndefined();  //<-- FAIL!       
    }));
});

scope代わりに変数を使用することになりましたが、最初のテストでは、コントローラー内の関数変数ctrl.$scopeを単体テストする方法がわかりませんでした。

コントローラ:

 function EmployeeCtrl($scope, $http, $filter, Employee) {
  var searchMatch = function (haystack, needle) {
   return false;
  }
 }

壊れた単体テスト:

it('should search ', function () {                
    expect(ctrl.searchMatch('numbers','one')).toBe(false);
});

これは私が得るものです

TypeError:オブジェクト#にはメソッド'searchMatch'がありません

その機能をどのようにテストしますか?回避策として、メソッドを$ scopeに移動してテストできるようにしましscope.searchMatchたが、これが唯一の方法かどうか疑問に思いました。

最後に、私のテストで$filter は未定義であるように見えますが、どのように注入しますか?私はこれを試しましたが、機能しませんでした:

ctrl = $controller('EmployeeCtrl', { $scope: scope, $filter: $filter });

ありがとう

更新: $filterを注入する上記の方法は問題なく機能します。

4

4 に答える 4

40

私の理解では、Angularjsでは、アプリケーションの起動時にスコープオブジェクトをコントローラーに渡し、コントローラーがスコープを変更します。コントローラはもう呼び出されません。

Angularjsでコントローラーが実際に行っているのは、スコープの初期化です。コントローラーは1回だけ実行されます。これを理解すると、次のようなスコープをコントローラーに要求していることがわかります。

currentScope = myController.scope;

意味がありません。

(ちなみに、Angularで私が気に入らないことの1つは、彼らが選択した名前です。「コントローラー」がスコープの初期化を行っている場合、それは実際にはコントローラーではありません。Angularにはこれがたくさんあります。 API)。

「コントローラー」をテストするための「適切な」方法は、Jasmine beforeEach句で最初から新しい空白のスコープを作成し、次のように新しい空白のスコープを初期化するために「コントローラー」を使用することだと思います。

var ctrl, myScope;

beforeEach(inject(function($controller, $rootScope) {
    myScope = $rootScope.$new();
    ctrl = $controller('myController', {
        $scope: myScope
    });
}));

そして、新しく作成されたスコープをテストすると、期待されるプロパティが得られます。

it('In the scope, the initial value for a=2', function() {
            expect(myScope.a).toBe(2);
});

つまり、コントローラーをテストしません。コントローラが作成したスコープをテストします。

だから、あなたはそれを正しくやっています。

于 2013-01-11T09:07:58.387 に答える
3

従うのがより簡単かもしれない別のパターンは次のとおりです。

var $scope;
beforeEach(module(function ($provide) {
  $scope = {
    // set anything you want here or nothing
  };
  $provide.value('$scope', $scope);
}));

var ctrl;
beforeEach(inject(function ($controller) {
  ctrl = $controller('MyController');
}));

it('should test something...', function () {
  // $scope will have any properties set by
  // the controller so you can now do asserts
  // on them.
});

これと同じパターンを使用して、$locationや$windowなどの値を設定できます。

于 2014-10-04T23:01:08.513 に答える
1

可能性は2つだけです。

searchMatchスコープに追加する(あなたが言ったように)または

searchMatch関数を返します。

function EmployeeCtrl($scope, $http, $filter, Employee) {
  return {
    searchMatch: function (haystack, needle) {
      return false;
    }
  };
 }

本当にプライベートのままにする必要がある場合は、それを使用する機能をテストする必要があります。

を取得するには$filter、次のことを試してください。

var $filter = angular.injector(['ng']).get('$filter'); 
于 2013-01-07T20:01:08.773 に答える
0

フィルタをテストするには、次の手順を実行してターゲットフィルタを取得します。

var ctrl, myScope, $filter;
beforeEach(inject(function(_$filter_){
    $filter = _$filter_;
}))

フィルタの名前が「AccountTimeZone」の場合は、次のようにします。

let accountTimeZoneFilter = $filter('AccountTimeZone');
于 2021-05-24T07:48:38.313 に答える