16

我试图从指令中监视 $emit,但不知何故我无法让间谍“听到”$emit。

这是我的指令控制器中的代码:

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

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

这是否与 $emit 不是向下广播而是向上广播有关,如果是,我该如何捕捉它,如果不是,我该如何处理这种情况?

4

2 回答 2

18

根据此处$emit的文档,您对and之间区别的理解是正确的$broadcast。但是,我认为问题在于您对$scopeand的使用$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');

我很确定这应该可以解决您的问题。让我知道是否需要更多解释。

于 2013-10-15T15:18:57.063 回答
3

如果您的指令有一个控制器,您可以并且应该与指令分开测试它。这就是 MVC 架构的全部意义所在,您可以将 C 与 V 分开测试。;)

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

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

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

于 2013-10-15T15:25:40.630 回答