单元测试间谍$ emit

时间:2013-10-15 14:19:49

标签: angularjs unit-testing angularjs-directive

我正在试图窥探指令中的$ emit,但不知怎的,我无法让间谍'听到'$ emit。

这是我的指令'controller:

中的代码
$scope.$on('send', function () {
    console.log('called');
    $scope.$emit('resultSend', {'ok': true, 'data': ''});
});

这是我的单元测试:

var $rootScope, $compile, elm, element;

beforeEach(inject(function ($injector) {
    $rootScope = $injector.get('$rootScope');
    $compile = $injector.get('$compile');
    elm = angular.element('<test></test>');
    element = $compile(elm)($rootScope);
}));


it('should listen for the send broadcast and emit the resultSend', function () {
    spyOn($rootScope, '$emit');
    $rootScope.$broadcast('send');
    expect($rootScope.$emit).toHaveBeenCalledWith('resultSend');
});

console.log输出('called')由Karma打印出来,所以我猜单元测试广播事件确实有效。

这是否与$ emit相关而不是向下播放,如果是这样,我该如何捕获它,如果没有,我该如何处理这种情况呢?

2 个答案:

答案 0 :(得分:16)

根据文档here,您对$emit$broadcast之间区别的理解是正确的。但是,我认为问题在于您使用$scope$rootScope。您的$rootScope将位于范围层次结构的顶层。我猜测(只是通过查看你的代码片而不能看到所有代码)控制器中的$scope是一个嵌套控制器,这意味着控制器中的$scope是一个孩子的应用$rootScope

因此,当您的单元测试在$rootScope.$emit功能上进行监听时,它实际上并没有监视您的控制器的$scope.$emit()电话。这两个“范围”是不同的,不一样的。因此,您需要模拟为控制器提供的$scope,然后对其执行spyOn

例如,在beforeEach

var ctrl, scope;

beforeEach(function() {
    module('<INSERT YOUR CONTROLLERS MODULE NAME HERE>'); 
    inject(function($rootScope, $controller) {
        scope = $rootScope.$new();
        ctrl = $controller('<CTRL NAME HERE>', {$scope: scope});
    });
});

这段代码实际上会创建一个“模拟”范围变量,并将该对象提供给您的控制器,然后您可以使用它来执行间谍和其他操作。如:

spyOn(scope, '$emit');
// do whatever triggers the "$emit" call
expect(scope.$emit).toHaveBeenCalledWith('resultSend');

我很确定应该解决你的问题。如果需要更多解释,请告诉我。

答案 1 :(得分:3)

如果你的指令有一个控制器,你可以而且应该和指令分开测试。这就是MVC架构的重点,你可以从V中单独测试C ;;)

那就是说,这将是一个简单的Jane控制器测试规范。

另一个提示:您应该在beforeEach()块中进行所有设置(即间谍等),然后在it()块中执行断言。

最后:确保您正在设置的间谍在您正在测试的控制器的范围内。