如何检查实例化控制器中的函数是否可用以在 Jasmine 中进行单元测试

How to check if a function is available in instantiated controller for unit testing in Jasmine

我第一次尝试在 AngularJS 中对控制器进行单元测试。我想测试此控制器中的登录功能是否调用了正确的服务,但我收到错误消息,该功能在控制器中不存在。我做错了什么?我必须嘲笑更多吗?但是我不必模拟要测试的控制器中的功能,因为如果我这样做,整个测试将毫无意义,或者我错了吗?

控制器代码段:

function LoginController($scope, $state, myService, ngToast) {

    $scope.loginUser = loginUser;

    activate();
    function activate() {}

    function loginUser(credentials) {
       myService.authenticate(/*things*/);
    }
}

测试代码:

describe('Login Controller', function () {
'use strict';

//globals
var controller, scope;
var $controller, $state, myService, ngToast;

//needed modules
beforeEach(module('app.login'));
beforeEach(module('app.core'));    
beforeEach(module('ui.router'));

//instanciate Controller        
beforeEach(inject(function (_$controller_, _$state_, _myService_,  _ngToast_) {
    scope = {};
    $state = _$state_;
    myService = _myService_;
    ngToast = _ngToast_;

    $controller = _$controller_;

    controller = $controller('LoginCtrl', {
        $scope: scope,
        $state: $state,
        myService: myService,
        ngToast: ngToast
    });
}));

it('should have an existing controller', function () {
    expect(controller).toBeDefined();
});

/*************************** unit-tests ***************************/
describe('.loginUser()', function () {
    it('should exist', function () {
        expect(controller.loginUser).toBeDefined();
    });
});
});

运行 karma 开始时出现的错误:

.loginUser()
  ✗ should exist
TypeError: controller.loginUser is not a function
    at Object.<anonymous> (src/login/login.controller.spec.js:74:31)

但在我看来控制器确实存在,因为这个测试没有失败:

Login Controller
 ✓ should have an existing controller

这是因为 loginUser 是在 $scope 而不是控制器上定义的,所以 loginUser 没有绑​​定到您测试中的控制器对象。

要测试登录用户,请执行以下操作:

  • 在你的 beforeEach 中注入 $rootScope
  • 设置范围 = $rootScope.$new()
  • 应使用此范围创建控制器
  • 你的测试应该检查 loginUser 是否定义在范围内

        describe('Login Controller', function () {
         'use strict';
    
         //globals
         var controller, scope;
        var $controller, $state, myService, ngToast;
    
        //needed modules
        beforeEach(module('app.login'));
        beforeEach(module('app.core'));    
        beforeEach(module('ui.router'));
    
        //instanciate Controller        
        beforeEach(inject(function (_$controller_, _$state_, _myService_,  _ngToast_, _$rootScope_) {
             scope = _$rootScope_.$new();
             $state = _$state_;
             myService = _myService_;
             ngToast = _ngToast_;
    
             $controller = _$controller_;
    
             controller = $controller('LoginCtrl', {
              $scope: scope,
              $state: $state,
              myService: myService,
              ngToast: ngToast
             });
           }));
    
        it('should have an existing controller', function () {
             expect(controller).toBeDefined();
           });
    
         /*************************** unit-tests ***************************/
         describe('.loginUser()', function () {
            it('should exist', function () {
               expect(scope.loginUser).toBeDefined();
        });
    });
    });
    

如果您想在控制器本身上测试 loginUser,则使用控制器作为语法,您可以在其中设置 this.loginUser = loginUser 而不是 $scope.loginUser = loginUser。然后你就可以在你的测试中使用controller.loginUser。