使用使用sinon返回promise的函数对angularJs服务进行存根

时间:2015-06-09 16:07:34

标签: angularjs jasmine sinon

我正在尝试测试在服务上调用方法的控制器。 service方法返回一个promise,控制器在调用service方法后立即调用.then() inline。我正在尝试使用sinon存根服务,并且Jasmine不断抛出错误,指出then未定义且不是函数。

这是控制器:

var loginModalController = function ($scope, authenticationService) {

    this.submit = submit;

    function submit(user, password) {
        $scope.email = user;
        authenticationService.login(user, password)
                .then(handleSuccessLogin, handleErrorLogin);
    }
}

这是服务:

function authenticationService($http, $q, endPointService) {

    var baseUri = endPointService.getApiEndpoint();

    var service = {
        getTermsAndConditions: getTermsAndConditions,
        login: login,
        acceptTerms: acceptTerms
    };

    return service;

    function getTermsAndConditions() {
        ...
    };

    function login(user, password) {
        var deferred = $q.defer();
        $http({ method: 'POST', url: baseUri + '/api/tokens', data: { username: user, password: password } }).
           success(function (data, status, headers, config) {
               $http.defaults.headers.common.Authorization = 'Basic ' + data.EncryptedTokenId;
               deferred.resolve(data);
           }).
           error(function (data, status, headers, config) {
               deferred.reject(status);
           });
        return deferred.promise;
    };

    function acceptTerms() {
        ...
    };
}

这是测试:

describe('loginModalController', function () {
    var scope, loginModalController, authenticationServiceMock, localSaverServiceMock;
    var loginInformationMock = { 'firstName': 'Testuser' };

    beforeEach(function () {
        module('clientAppModule');

        inject(function ($rootScope, $controller, authenticationService, localSaverService) {
            scope = $rootScope.$new();

            authenticationServiceMock = sinon.stub(authenticationService)
                .login.returns({ then: function () { return loginInformationMock } });

            localSaverServiceMock = sinon.stub(localSaverService);

            loginModalController = $controller('loginModalController', {
                $scope: scope,
                $state: {},
                authenticationService: authenticationServiceMock,
                errorCodes: {}, 
                localSaverService: localSaverServiceMock
            });
        });
    });

    it('should login', function () {
        loginModalController.submit("test", "test");
    });
});

1 个答案:

答案 0 :(得分:0)

我的代码有四个问题:

  • 我不必要地使用Sinon
  • 我使用的是stub()的返回值,而不仅仅是让它存根服务。
  • 我没有使用$q返回延迟的保证以匹配登录功能。
  • 我需要在范围内调用$digest()以获得在断言之前解决的延迟承诺。

所以这是固定的测试代码:

beforeEach(module('clientAppModule'));

describe('loginModalController', function () {
    var scope, authenticationService, localSaverService;
    var loginInformationMock = { 'firstName': 'Testuser' };

    beforeEach(inject(function ($injector, $rootScope, $controller, $q) {

        scope = $rootScope.$new();
        scope.$close = function () { };

        authenticationService = $injector.get('authenticationService');
        localSaverService = $injector.get('localSaverService');            

        spyOn(authenticationService, 'login').and.callFake(function () {
            var deferred = $q.defer();
            deferred.resolve(loginInformationMock);

            return deferred.promise;
        });
        spyOn(localSaverService, 'saveLoginInformation').and.stub();

        $controller('loginModalController', {
            $scope: scope,
            $rootScope: {},
            $state: {},
            authenticationService: authenticationService,
            errorCodes: {},
            localSaverService: localSaverService
        });
    }));

    it('should call login on authenticationService', function () {
        // Arrange

        // Act
        scope.submit("test", "test");

        // Assert
        expect(authenticationService.login).toHaveBeenCalled();
    });

    it('should save login info after successful login', function () {
        // Arrange

        // Act
        scope.submit("test", "test");
        scope.$digest();

        // Assert
        expect(localSaverService.saveLoginInformation).toHaveBeenCalled();
    });
});