在Angular单元测试中测试控制器初始化过程

时间:2015-08-13 20:59:41

标签: angularjs unit-testing sinon

是否可以测试Angular控制器的init进程?

以下是代码:

var app = angular.module('led', []);
app.controller('zeppelin', ['$scope', function ($scope) {
    $scope.love = function () {
        return 2;
    };

    $scope.tangerine = $scope.love();
    $scope.prove = function () {
        $scope.love();
    };

    $scope.prove();
    $scope.love();
}]);

测试代码:

scope = _$rootScope_.$new();
controller = _$controller_('zeppelin', {
    $scope: scope
});

proved = sinon.spy();
loved = sinon.stub().returns(7);
scope.prove = proved;
scope.love = loved;
expect(proved.callCount).toBe(1); //=> 0
expect(loved.callCount).toBe(2); //=> 0
scope.prove();
expect(proved.callCount).toBe(2); //=> 1
expect(loved.callCount).toBe(3); //=> 0

我对上述代码的问题是:

  1. 我知道由于控制器已经初始化,期望会失败。如果我在初始化之前设置 scope.prove = spied ,那么即使在显式调用它们之后,我也会收到0。是否有一种测试init过程的工作方法?
  2. 如何存根 scope.love ,以便 scope.tangerine 从存根中接收数据,而不是从控制器接收数据?
  3. 为什么在致电 scope.prove()后, loved.callCount 不会增加?
  4. 对我来说,最好的情况是 3 ,因为我无法想到对这种奇怪行为的任何合理解释。

2 个答案:

答案 0 :(得分:1)

<强> 1

控制器只是一个接受$scope对象作为参数的构造函数。您正在定义范围

上的函数
$scope.love = function () {
    return 2;
};
$scope.prove = function () {
    $scope.love();
};

然后立即调用它们

$scope.prove();
$scope.love();

在控制器结束时首次调用函数之前,无法拦截此过程(在Angular中或一般情况下)监视函数。如果您在初始化控制器之前设置了$scope.prove = spied ,那么控制器就会覆盖它,如果您在之后设置,那么当间谍将不存在时这些函数被调用。

<强> 2

由于上述原因,您无法及时存根$scope.love,以便将其返回值分配给$scope.tangerine。如果能够在测试中修改控制器初始化行为对您来说真的很重要,那么您应该使love和注入服务将其注入控制器,并在测试中模拟它。

第3

您的间谍($scope.prove)会覆盖

scope.prove = proved。您正在丢失在控制器中创建的原始函数,该函数调用$scope.love。相反,你需要监视现有的功能。例如,

var controller = $controller('zeppelin', { $scope: scope });

// here, the controller has initialized scope.prove and scope.love
var loved = sinon.spy(scope, 'love');
var proved = sinon.spy(scope, 'prove');

scope.prove();

// both callCounts are incremented
expect(proved.callCount).toBe(1);
expect(loved.callCount).toBe(1);

答案 1 :(得分:0)

看起来只有范围才能在控制器的init进程上进行测试。可以测试任何其他依赖项,因为事先知道它们的状态。

一些确认代码:

app.controller('zeppelin', ['$scope','hangman', function ($scope, hangman) {
$scope.love = function () {
    hangman.a(4,6);
    return 'sweet';
};
$scope.tangerine = $scope.love();
$scope.prove = function () {
    $scope.love();
    hangman.a(4,$scope.tangerine);
};
hangman.a(4,6);
}]);

测试代码:

beforeEach(inject(function (_$rootScope_, _$controller_, _hangman_) {
    sandbox = sinon.sandbox.create();
    scope = _$rootScope_.$new();
    hangman = _hangman_;
    blackDog = sinon.spy(hangman, 'a');
    loved = sinon.spy(scope, 'love');
    controller = _$controller_('zeppelin', {
        $scope: scope,
        hangman: hangman
    });
    proved = sinon.spy(scope, 'prove');
}));
it('should x', function () {
    scope.prove();
    scope.love();
    expect(scope.tangerine).toBe('sweet');
    expect(loved.callCount).toBe(2);
    expect(blackDog.callCount).toBe(5);
    expect(proved.callCount).toBe(1);
});