Angular - 嘲笑返回promise的服务方法

时间:2015-03-25 22:14:17

标签: angularjs jasmine

我正在尝试测试依赖于服务调用来获取某些数据的控制器方法。 service方法返回一个promise,如果promise被解决或拒绝,我想测试控制器的行为。

我已经提出了这种方法来改变我的模拟服务方法的行为,但它不起作用。调用模拟的getDataSuccess方法时,getData标志始终为true。这就是我到目前为止所拥有的:

控制器:

app.controller('myController', function($scope, myService) {
       myService.getData()
         .then(function (data) {
             $scope.data = data;                   
         },
         function (data) {
             $scope.serverError = data;
         });
});

测试:

describe('myController', function () {

    var ctl, serviceMock, getDataSuccess, scope;

    beforeEach(function() {
            getDataSuccess = true;
            serviceMock = {};

        module('app', function ($provide) {
            $provide.value('myService', serviceMock);
        });      

        inject(function ($q) {
            serviceMock.getData = function () {                
                var defer = $q.defer();
                if (getDataSuccess) {
                    defer.resolve("theData");
                } else {
                    defer.reject("theData");
                }
                return defer.promise;
            };
        });
    });

    beforeEach(inject(function ($rootScope, $controller, $httpBackend, myService) {

        scope = $rootScope.$new();

        ctl = $controller('myController', {
            $scope: scope,          
            myService: myService,
        });        
    }));

    describe('myController loading data', function () {

        it('should set $scope.data if data load succeeds', function () {
            getDataSuccess = true;
            scope.$apply();
            expect(scope.data).toEqual("theData");
        });

        it('should set $scope.serverError if data load fails', function () {
            getDataSuccess = false;
            scope.$apply();
            expect(scope.serverError).toEqual("theData");
        });

    });

});

显然,我在这里遗漏了一些东西。执行顺序不是我所期待的。做这种事情的正确方法是什么?

这是Plunker中的这个例子:http://plnkr.co/edit/ODyslivLorjaLM4EqlEF?p=preview

1 个答案:

答案 0 :(得分:1)

调用myService.getData函数,其中myController被初始化。因此,如果要通过设置getDataSuccess来更改行为getData函数,则需要在设置getDataSuccess true / false后初始化myController。

我推荐的是这样的。

在appSpec.js

describe('myController', function () {

    var ctl, serviceMock, getDataSuccess, scope;

    beforeEach(function() {
        getDataSuccess = true;
        serviceMock = {};

        module('app', function ($provide) {
            $provide.value('myService', serviceMock);
        });      

        inject(function ($q) {
            serviceMock.getData = function () {                
                var defer = $q.defer();
                if (getDataSuccess) {
                    defer.resolve("theData");
                } else {
                    defer.reject("theData");
                }
                return defer.promise;
            };
        });
    });

    beforeEach(inject(function ($rootScope, $controller, $httpBackend, myService) {
        scope = $rootScope.$new();
//      
//        ctl = $controller('myController', {
//            $scope: scope,          
//            myService: myService,
//        });        
    }));

    describe('myController loading data', function () {

        it('should set $scope.data if data load succeeds', inject(function($controller, myService){
            getDataSuccess = true;
            ctl = $controller('myController', {
                $scope: scope,          
                myService: myService,
            });        
            scope.$apply();
            expect(scope.data).toEqual("theData");
        }));    

        it('should set $scope.serverError if data load fails', inject(function($controller, myService){
            getDataSuccess = false;
            ctl = $controller('myController', {
                $scope: scope,          
                myService: myService,
            });        
            scope.$apply();
            expect(scope.serverError).toEqual("theData");
        }));    

    });

});

This is updated plunker.