【问题标题】:Testing angular controller initialisation with different conditions在不同条件下测试角度控制器初始化
【发布时间】:2015-01-16 05:50:02
【问题描述】:

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

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';
        }
});

当 key 不存在时的测试失败,因为控制器初始化已经在第一个 beforeEach 中运行,在下一个 beforeEach 运行以更改服务返回值之前。

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

这是初始化控制器的正确方法吗?我错过了茉莉花的一些功能吗?

【问题讨论】:

    标签: angularjs jasmine


    【解决方案1】:

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

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

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

    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 拦截对服务的调用并决定它应该返回什么,然后创建控制器:

    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。旧版本的语法必须稍作修改。

    【讨论】:

    • 谢谢,这是有道理的,我想我想在 beforeEach 中创建控制器,这样每个测试都会获得一个控制器,而不必记住在每个“it”函数中调用“createController”。但是在每个测试中设置控制器可以清楚地表明测试都需要控制器......
    猜你喜欢
    • 1970-01-01
    • 2016-03-07
    • 1970-01-01
    • 1970-01-01
    • 2020-06-28
    • 1970-01-01
    • 1970-01-01
    • 2016-12-31
    • 1970-01-01
    相关资源
    最近更新 更多