48

在我的一些指令中,我将函数添加到范围以处理特定于指令的逻辑。例如:

link: function(scope, element, attrs) {
         scope.doStuff = function() {
            //do a bunch of stuff I want to test
         }        
      }

我该如何测试该功能?我搜索了如何测试指令,但我发现更多的是关于测试元素的更改。我当然可以在每次测试之前编译我的指令,但这每次都会清除我的范围。我想在我的范围更改中测试该函数作为属性。

有没有办法获取从指令定义返回的对象?然后我可以直接调用链接函数并测试作用域上定义的每个函数的行为。有没有更好的方法来完成这一切?

我正在使用 Jasmine 运行我的测试,并且我想在describe函数中设置我的范围,所以我可以it为相同的范围数据设置多个函数。

4

5 回答 5

46

基本上,不是测试链接函数本身,而是以编程方式测试指令的结果。你要做的就是将指令写成一个字符串,然后用$compile角度处理它。然后你测试输出以确保一切都正确连接。

Angular 的源代码充满了如何做到这一点的好例子……例如Angular 对 ngRepeat 指令的测试

您可以看到他们正在做的是设置指令,更改范围(在这种情况下$rootScope)确保它被$digest编辑,然后测试它输出的 DOM 以确保一切都正确连接。如果指令正在改变它,您还可以测试范围内的内容。

ngClick 的测试也很有趣,因为它显示了对浏览器交互的测试以及它对范围的影响。

为了完整起见,这里有一个来自 ngClick 测试的片段,我认为它很好地总结了测试指令:

 it('should get called on a click', inject(function($rootScope, $compile) {
   element = $compile('<div ng-click="clicked = true"></div>')($rootScope);
   $rootScope.$digest();
   expect($rootScope.clicked).toBeFalsy();

   browserTrigger(element, 'click');
   expect($rootScope.clicked).toEqual(true);
 }));

所以在你的scope.doStuff函数的情况下,我不会测试它在做什么,就像我会测试它在范围内影响的任何东西,然后它会影响 DOM 元素。

于 2012-11-16T15:59:56.427 回答
2

如果需要,可以直接对指令的链接方法进行单元测试。请参阅 angular-ice 模块的单元测试器:“测试指令配置”

http://bverbist.github.io/angular-ice/#/unitTester

示例用法:https ://github.com/bverbist/angular-ice/blob/master/app/components/icebank/bank-account-number-directive_link_test.js

在您的情况下,您可以保留对传递给指令链接方法的范围对象的引用,然后您可以直接在该范围上测试 doStuff 函数。

于 2015-08-03T21:59:39.810 回答
1

我以不同的方式解决了这个问题。

如果您的指令中有一个非常简单的链接函数并且您不需要第三个参数(attrs),只需摆脱链接函数并为指令分配一个控制器

app.directive('loadIndicator', function() {
  return {
    restrict: 'E',
    replace: true,
    templateUrl: 'blahblah/indicator.html',
    controller: 'LoadIndicatorController'
  };
});

就像您在指令的链接函数中拥有范围和元素的参数一样,这两个参数可以作为$scope$element注入到易于测试的控制器中。

如果您能够创建控制器并对这些控制器进行单元测试,那么这将非常容易做到。

于 2014-10-28T23:44:36.617 回答
0

正如对@sqlexception 的评论回复中所述。您只需要真正掌握指令的范围,这并不难。你不想做的是修改你的代码以满足你的测试,因为它应该是相反的。

要获得指令的范围,只需像这样编译:

var element = $compile(<directive's html>).($scope)

where$scope$scope = $rootScrope.$new(). 现在我们可以通过做得到隔离范围element.scope()

我最近刚刚写了一篇关于这个的简短博客文章,在这里找到了用 plunker测试链接函数 来提供帮助:

于 2015-02-05T18:02:47.623 回答
0
 it('should get called on a click', inject(function($rootScope, $compile) {
   var scope = $rootScope.$new();
   element = $compile('<div ng-click="doIt()"></div>')(scope);
   scope.$digest();
   expect(scope.$$childHead.doIt()).toBeDefined();
 }));

使用这个 $$childHead 是我解决同样问题的方法,这样我可以覆盖在我的测试中没有被调用的函数。

于 2018-10-12T17:05:51.110 回答