6

次のコントローラーがあります (インスタンス化時に を明示的に呼び出すことに注意して$scope.getNotifications()ください)。

bla.controller("myctrl", [
    "$scope", "$http", "configs", function ($scope, $http, configs) {

        $scope.getNotifications = function () {
            $http.get("bla/blabla").success(function (data) {

            });
        };

        $scope.removeNotification = function (notification) {
            var index = $scope.allNotifications.indexOf(notification);
            $scope.allNotifications.splice(index, 1);
        };

        $scope.getNotifications();
    }
]);

次に、いくつかの単体テストを行います (コントローラーがそれぞれの前にインスタンス化されることに注意してください)。

describe("blaController", function () {

    var scope, $httpBackend;

    beforeEach(module('bla'));

    beforeEach(inject(function ($controller, $rootScope, _$httpBackend_) {
        scope = $rootScope.$new();
        $httpBackend = _$httpBackend_;
        $controller('blaCtrl', { $scope: scope });
    }));

 afterEach(function(){
    //assert
    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();
 });

 it("should get all notifications from server when instantiated", function () {
    //arrange
    $httpBackend.expectGET("api/v1/notifications").respond(200, {});
    $httpBackend.flush();

    //act - done implicitly when controller is instantiated  
});

it("should store all notifications from server on the client when success call to server", function () {
    //arrange
    $httpBackend.whenGET("api/v1/notifications").respond(200, [{ a: 1, b: 2 }, { c: 3, d: 4 }]);
    $httpBackend.flush();

    //act - done implicitly when controller is instantiated

    //assert
    expect(scope.allNotifications).toEqual([{ a: 1, b: 2 }, { c: 3, d: 4 }]);
});

今まではすべて順調です。すべてのテストに合格します。しかし、HTTP 呼び出しを必要としない新しいテスト (以下を参照) を追加すると失敗しafterEach()ますremoveNotification()。これはカルマからのエラー メッセージです: PhantomJS 1.9.7 (Windows 8) notificationCenterController removeNotification should remove the given notification from the list FAILED Error: Unexpected request: GET api/v1/notifications No more request expected

it("should remove the given notification from the list", function () {
            //arrange
            var targetObj = { a: 2 };
            scope.allNotifications = [{ a: 1 }, targetObj, { a: 3 }];

            //act
            scope.removeNotification(targetObj);

            //assert
            expect(scope.allNotifications).toEqual([{ a: 1 }, { a: 3 }]);
        });

私のテストのほとんどには http 呼び出しがあるため、afterEach に検証を配置することは理にかなっています。N-1 テストで afterEach ボディをコピーして貼り付けるのを避けるために、他にどのようなオプションが必要か疑問に思っていました。電話を無視するように指示する方法はありますか?$httpBackend

4

3 に答える 3

3

以下のように記述ブロックでテストをラップできます。

describe("blaController", function () {

    var scope, $httpBackend;

    beforeEach(module('bla'));

    beforeEach(inject(function ($controller, $rootScope, _$httpBackend_) {
        scope = $rootScope.$new();
        $httpBackend = _$httpBackend_;
        $controller('blaCtrl', { $scope: scope });
    }));

    describe('test http calls', function() {

        afterEach(function(){
            //assert
            $httpBackend.verifyNoOutstandingExpectation();
            $httpBackend.verifyNoOutstandingRequest();
        });

        it("should get all notifications from server when instantiated", function () {
            //arrange
            $httpBackend.expectGET("api/v1/notifications").respond(200, {});
            $httpBackend.flush();

            //act - done implicitly when controller is instantiated  
        });

        it("should store all notifications from server on the client when success call to server", function () {
        //arrange
            $httpBackend.whenGET("api/v1/notifications").respond(200, [{ a: 1, b: 2 }, { c: 3, d: 4 }]);
            $httpBackend.flush();

            //act - done implicitly when controller is instantiated

            //assert
            expect(scope.allNotifications).toEqual([{ a: 1, b: 2 }, { c: 3, d: 4 }]);
        });

    }); 

    describe('other tests', function(){
        it("should remove the given notification from the list", function () {
            //arrange
            var targetObj = { a: 2 };
            scope.allNotifications = [{ a: 1 }, targetObj, { a: 3 }];

            //act
            scope.removeNotification(targetObj);

            //assert
            expect(scope.allNotifications).toEqual([{ a: 1 }, { a: 3 }]);
        });
    });
});
于 2016-06-07T09:48:28.657 に答える
1

別のスイートで $http.get をスパイできますが、これは機能するはずです (以下の疑似コード)。

 describe("backend", function() { // your code from before });

 describe("non-backend", function () {

    var scope, $http;

    beforeEach(module('bla'));

    beforeEach(inject(function ($controller, $rootScope, _$http_) {
        scope = $rootScope.$new();
        $http = _$http_;
        spyOn($http, 'get').and.callFake(function() {
            return { some: 'data' };
        });
        $controller('blaCtrl', { $scope: scope, $http: $http });
    }));

    it("should remove the given notification from the list", function () {
        //arrange
        var targetObj = { a: 2 };
        scope.allNotifications = [{ a: 1 }, targetObj, { a: 3 }];

        //act
        scope.removeNotification(targetObj);

        //assert
        expect(scope.allNotifications).toEqual([{ a: 1 }, { a: 3 }]);
    });
});
于 2016-06-07T09:08:14.933 に答える
1

コンストラクターで http 要求を行っており、テストを実行するたびにコンストラクターが実行されているため、 はhttpBackend毎回この要求に応答できるように準備する必要があります。

したがって、beforeEachブロックで次のように設定する必要があります。

notificationsRequest = $httpBackend.expectGET("api/v1/notifications").respond(200, {});

テスト ケースでは、respond メソッドを再度呼び出すことで、この応答を変更できます。これにより、次のように応答セットが上書きされます。

it("should store all notifications from server on the client when success call to server", function () {
    //arrange
    notificationsRequest.respond(200, [{ a: 1, b: 2 }, { c: 3, d: 4 }]);
    $httpBackend.flush();

    //act - done implicitly when controller is instantiated

    //assert
    expect(scope.allNotifications).toEqual([{ a: 1, b: 2 }, { c: 3, d: 4 }]);
});

あとは、各テストの後に応答をフラッシュしていることを確認するだけです。これは便利ではないかもしれませんがverifyNoOutstandingRequest、コンストラクターの定義により、未解決の要求があるため、必要に応じて実行する必要があります。テストをネストされたスイートに構造化し、通知の取得をテストしていないものについては、独自のbeforeEachブロックでリクエストをフラッシュすることでこれを行うことをお勧めします。

于 2016-06-07T09:48:03.753 に答える