在不同条件下测试 angular 控制器初始化

Testing angular controller initialisation with different conditions

我有一个依赖于服务的控制器,并且作为其初始化的一部分调用服务上的函数。这是一个人为的例子:

describe('tests', function() {
    var _scope, service, serviceValue = 'value';
    beforeEach(module('app'));
    beforeEach(inject(['$rootScope','$controller', function($rootScope, $controller) {
        _scope = $rootScope.$new();
        service = {
            get: function(key) {
                return serviceValue;
            }
        };

        $controller('myController', {
            '$scope': _scope,
            'service': service
        });
    }]));

    describe('initialisation', function() {
        describe('key exists', function() {
            it('should find the key', function() {
                expect(_scope.message).toBe('found the key');
            });
        });

        describe('key does not exist', function() {
            beforeEach(function() {
                serviceValue = undefined;
            });

            it('should not find the key', function() {
                expect(_scope.message).toBe('did not find the key');
            });
        });
    });
});

angular.module('app').controller('myController', ['$scope','service',
    function($scope, service) {
        if(service.get('key') === 'value') {
            $scope.message = 'found the key';
        } else {
             $scope.message = 'did not find the key';
        }
});

当键不存在时的测试失败,因为控制器初始化在第一个 beforeEach 中有 运行,在下一个 beforeEach 运行s 之前更改服务 return 值.

我可以通过在 'key does not exist' 测试的 beforeEach 中重新创建整个控制器来解决这个问题,但这对我来说似乎是错误的,因为它会为测试初始化​​控制器两次。有没有办法让每次测试的控制器初始化为 运行,但在所有其他 beforeEach 函数都有 运行 之后。

这是初始化控制器的正确方法吗?我是否遗漏了 jasmine 的某些功能?

为每个测试创建控制器是推荐的方法,尤其是当您有初始化逻辑时。

不过,我会使用 Jasmine 的 spyOn 来设置服务 return 并跟踪对其调用的内容,而不是修改模拟或真实服务的内部值。

注入真正的服务并将其保存在一个变量中,并定义一个创建控制器的函数:

describe('tests', function() {

  var $scope, createController, service;

  beforeEach(function() {

    module('app');

    inject(function($rootScope, $controller, _service_) {

      $scope = $rootScope.$new();
      service = _service_;

      createController = function() {
        $controller('myController', {
          '$scope': $scope,
          'service': service
        });
      };
    });
  });

对于每个测试,使用 spyOn 拦截对服务的调用并决定它应该做什么 return,然后创建控制器:

describe('initialisation', function() {

  it('should find the key', function() {

    spyOn(service, 'get').and.returnValue('value');
    createController();

    expect($scope.message).toBe('found the key');
  });

  it('should not find the key', function() {

    spyOn(service, 'get').and.returnValue(undefined);
    createController();

    expect($scope.message).toBe('did not find the key');
  });
});

演示: http://plnkr.co/edit/BMniTis1RbOR0h5O4kZi?p=preview

由于 spyOn 设置了跟踪,您现在还可以确保服务仅在控制器初始化时被调用一次:

spyOn(service, 'get').and.returnValue('value');
expect(service.get.calls.count()).toEqual(0);
createController();
expect(service.get.calls.count()).toEqual(1);

注意:以上示例使用 Jasmine 2.0。旧版本的语法必须稍作修改。