如何在 Karma 测试中更改常量值

How to change constant value in a Karma test

我有一个 Angular 指令,它根据注入常量的值设置一些 $scope 属性 的值。我想测试这个值是否从常量正确初始化,所以我想在单个 it 块中更改常量的值。 (最好在一个内,但在多个块之间更改值也可以)

这可能吗,我该怎么做?

简化示例:

//////// directive ////////
angular.module('myApp.directives', [])
.constant('THE_CONSTANT', 'hello world')
.directive('myDirective', ['THE_CONSTANT', function (THE_CONSTANT) {

    return {
        restrict: 'E',
        link: function ($scope) {
            $scope.propertyBasedOnConstant = THE_CONSTANT;
        }
    };
}]);

//////// test ////////
describe('myDirective', function () {
    var $element, $scope;

    beforeEach(module('myApp.directives'));

    beforeEach(module(function ($provide) {
        $provide.constant('THE_CONSTANT', 'foo');
    }));

    beforeEach(inject(function ($rootScope, $compile) {
        $scope = $rootScope;
        $element = angular.element('<my-directive></my-directive>');
        $compile($element)($scope);
        $scope.$digest();
    }));

    afterEach(function () {
        $scope.$destroy();
        $element.remove();
    });

    it("should correctly reflect the constant's value", function() {
        expect( $scope.propertyBasedOnConstant ).to.equal('foo');

        // now I want to change the constant's value and re-initialize the directive
    });    
});

根据定义,常量是具有无法更改的关联值的标识符。为什么不注入常量本身并在您的期望范围内使用它,而不是更改常量值。

describe('myDirective', function () {
    var $element, $scope,
      THE_CONSTANT;

    beforeEach(module('myApp.directives'));

    beforeEach(module(function (_THE_CONSTANT_) {
      THE_CONSTANT = _THE_CONSTANT_;
    }));

    beforeEach(inject(function ($rootScope, $compile) {
        $scope = $rootScope;
        $element = angular.element('<my-directive></my-directive>');
        $compile($element)($scope);
        $scope.$digest();
    }));

    afterEach(function () {
        $scope.$destroy();
        $element.remove();
    });

    it("should correctly reflect the constant's value", function() {
        expect( $scope.propertyBasedOnConstant ).to.equal(THE_CONSTANT);
    });    
});

您正在将 constant 提供给 undefined 模块。

将您的 beforeEach 块更改为类似这样的内容,它 应该可以正常工作™:

var $scope, $element, MOCKED_CONSTANT;

beforeEach(function () {
  MOCKED_CONSTANT = 'foo';

  module('myApp.directives', function ($provide) {
    $provide.constant('THE_CONSTANT', MOCKED_CONSTANT);
  });

  inject(function ($rootScope, $compile) {
    $scope       = $rootScope.$new(); // Don't forget to call .$new()!
    var template = angular.element('<my-directive></my-directive');
    $element     = $compile(template)($scope); // Store the reference to the compiled element, not the raw string.
    $scope.$digest();
  });
});

it("should correctly reflect the constant's value", function() {
  expect( $scope.propertyBasedOnConstant ).to.equal(MOCKED_CONSTANT);
  // expect( $scope.propertyBasedOnConstant ).to.equal('foo');
});

如果您需要更改 it 之间的常量值,我会将对 module 的调用以及 inject 的调用提取到辅助函数中。如:

function setupModule (constant) {
  module('myApp.directives', function ($provide) {
    $provide.constant('THE_CONSTANT', constant);
  });
}

function injectItAll () {
  inject(function ($rootScope, $compile) {
    $scope       = $rootScope.$new(); // Don't forget to call .$new()!
    var template = angular.element('<my-directive></my-directive');
    $element     = $compile(template)($scope); // Store the reference to the compiled element, not the raw string.
    $scope.$digest();
  });
}

然后在你的规范中你会做:

it('equals banana', function () {
  setupModule('banana');
  injectItAll();
  expect($scope.propertyBasedOnConstant).to.equal('banana');
});