AngularJS 使用返回承诺的服务测试控制器

AngularJS testing controller using a service returning a promise

我正在为我的组件编写单元测试。

我知道这个问题在研究了很多之前和之后都得到了回答,感觉测试依赖于服务的东西很麻烦或者需要脏活。

对我来说,以下感觉很脏,如果这是要走的路,我会征求你的意见:)

这是我的控制器

function Login($location, AuthService) {
    var vm = this;

    vm.error = "";

    vm.login = login;

    //////////

    function login(credentials) {
        AuthService.login(credentials)
            .then(function(user) {
                $location.path("/menu");
            })
            .catch(function(q) {
                vm.error = q.data.error;
            });
    }
}

考试准备,我假 $location 和我的 AuthService:

beforeEach(inject(function($q) {
    location = {
        path: function(q) { path = q; }
    };

    AuthService = {
        login: function(credentials) {
            deferred = $q.defer();
            if (credentials)
                deferred.resolve();
            else
                deferred.reject({ data: {error: "My Error"} });
            return deferred.promise;
        }
    };
}));

beforeEach(inject(function($rootScope, $controller) {
    scope = $rootScope.$new();
    Login = $controller('Login', {
        $location: location,
        AuthService: AuthService
    });
}));

和测试:

describe("(login)", function() {
    it('should redirect on successful login', function() {
        Login.login(true);
        scope.$root.$digest();
        expect(path).toBe("/menu");
    });

    it('should show error on failed login', function() {
        Login.login(false);
        scope.$root.$digest();
        expect(Login.error).toBe("My Error");
    });
});

一切正常,但使用全局变量和事后检查感觉很脏。

我感谢每一个意见和每一个更清洁的方法:)

我认为这会是一种更简洁的方法

beforeEach(inject(function(_$rootScope_, $controller, _AuthService_, _$location_, _$q_) {
    $rootScope = _$rootScope_;
    AuthService = _AuthService_;
    $location = _$location_;
    $q = _$q_;

    spyOn($location, 'path').and.stub();

    var scope = $rootScope.$new();
    Login = $controller('Login', { $scope: scope });
}));

describe("(login)", function() {
    it('should redirect on successful login', function() {
        spyOn(AuthService, 'login').and.returnValue($q.resolve());

        Login.login(true);
        $rootScope.$digest();
        expect($location.path).toHaveBeenCalledWith('/menu');
    });

    it('should show error on failed login', function() {
        spyOn(AuthService, 'login').and.returnValue($q.reject({
            data: {error: "My Error"}
        }));

        Login.login(false);
        $rootScope.$digest();
        expect(Login.error).toBe("My Error");
    });
});

path 全局看起来不太好(即使它是 describe 范围内的局部变量),你不必为他们做间谍的工作。