Angularjs 包含承诺的函数的单元测试未按预期工作

Angularjs 包含承诺的函数的单元测试未按预期工作,angularjs,unit-testing,jasmine,Angularjs,Unit Testing,Jasmine,我正在尝试对一个控制器进行单元测试,该控制器处理用户登录。我得到了一个错误,并认为这可能与使用承诺的代码有关,但我现在不太确定。这是控制器 angular.module('app').controller('SignIn', SignIn); function SignIn ($scope, $state, auth) { $scope.credentials = {}; // signin $scope.signIn = function () {

我正在尝试对一个控制器进行单元测试,该控制器处理用户登录。我得到了一个错误,并认为这可能与使用承诺的代码有关,但我现在不太确定。这是控制器

angular.module('app').controller('SignIn', SignIn);

function SignIn ($scope, $state, auth) {

    $scope.credentials = {};

    // signin
    $scope.signIn = function () {
        auth.signIn($scope.credentials)
            .then(function () {
                $state.go('user.welcome');
            }, function (res) {
                $scope.signInError = res.statusText;
            });
    };
}
这是授权服务

angular.module('app').factory('auth', auth);

function auth (session, api) {
    return {
        signIn : function (credentials) {
            return api.signIn(credentials)
                .then(function (res) {
                    session.create(res.data.sessionId, res.data.userName);
                });
        },
        signout: function () {
            return session.destroy();
        },
        isAuthenticated: function () {
            return !!session.userName;
        }
    };
}
api只返回$http承诺

signIn : function (credentials) {
    return $http.post(base + '/auth/credentials', credentials);
}
会话只是一个工厂,用于存储当前会话信息并将其保存到浏览器的cookie中

这是我的茉莉花测试

describe('SignIn', function () {

// setup ------------------------------------------------------------------

    // init app module
    beforeEach(module('app'));

    // inject Session service
    beforeEach(angular.mock.inject(function (_$rootScope_, _$controller_, _auth_) {
        $rootScope             = _$rootScope_;
        $scope                 = $rootScope.$new();
        controller             = _$controller_("SignIn", {$scope: $scope});
        auth                   = _auth_;
    }));

    // setup spies
    beforeEach(function () {
        spyOn(auth, 'signIn');
    });

// tests ------------------------------------------------------------------

    // signin in
    it("should call auth.signIn with the user's credentials", function () {
        $scope.signIn();
        expect(auth.signIn).toHaveBeenCalled();
    });

});
我只是想测试在调用$scope.signIn()时是否调用了auth.signIn。应用程序本身可以正常工作,但我在尝试运行此测试时遇到此错误

SignIn should call auth.signIn with the user's credentials FAILED
TypeError: 'undefined' is not an object (evaluating 'auth.signIn($scope.credentials).then')
尽管有一个期望,但当我调用$scope.signIn()时,错误正在发生;如果我在$scope.sign()之前登录auth;这叫我得到这个

LOG: Object{signIn: function () { ... }, signout: function () { ... }, isAuthenticated: function () { ... }}

因此,我假设DI按照预期工作。我已经研究过设置间谍的不同方法,但还没有弄清楚到底是什么错。任何帮助都将不胜感激。

这是因为您正在监视
auth
signIn
功能。当您监视它时,它将不再是api中真正的函数。所以你需要通过使用从间谍那里得到一个承诺

我们也要这样做:-

beforeEach(inject(function (_$rootScope_, _$controller_, _auth_, _$q_) {
    $rootScope             = _$rootScope_;
    $scope                 = $rootScope.$new();
    controller             = _$controller_("SignIn", {$scope: $scope});
    auth                   = _auth_;
    fakePromise = _$q_.when(); //get a fake promise
}));

beforeEach(function () {
  spyOn(auth, 'signIn').and.returnValue(fakePromise); //return fakepromise
});

如果要从signIn(或任何其他函数的承诺)返回一些值,只需执行


没有回答这个问题,但是在angular中围绕statusText有几个问题。也许最好不要在你的错误反馈中依赖它…谢谢,这是有效的,并且让错误变得有意义。我必须更改“.and.returnValue()”;to.andReturn();这可能是茉莉花版本的不同。$q.在做什么?如果不向其传递更多数据,是否只返回一个泛型承诺?是的$q。when()返回一个包含then和其他承诺方法的承诺对象
  fakeAuthPromise = _$q_.when(somedata);