2015-11-17 228 views
8

单元测试角度指令不是很难,但我发现有不同的方法来做到这一点。如何单元测试角度指令

对于这篇文章的目的,让我们假设下面的指令

angular.module('myApp') 
    .directive('barFoo', function() { 
     return { 
      restrict: 'E', 
      scope: true, 
      template: '<p ng-click="toggle()"><span ng-hide="active">Bar Foo</span></p>', 
      controller: function ($element, $scope) { 
       this.toggle() { 
        this.active = !this.active; 
       } 
      } 
     }; 
    }); 

现在我能想到的两种方法进行单元测试这个

方法1:

describe('Directive: barFoo', function() { 
    ... 
    beforeEach(inject(function($rootScope, barFooDirective) { 
     element = angular.element('<bar-foo></bar-foo>'); 
     scope = $rootScope.$new(); 
     controller = new barFooDirective[0].controller(element, scope); 
    })); 

    it('should be visible when toggled', function() { 
     controller.toggle(); 
     expect(controller.active).toBeTruthy(); 
    }); 
}); 

方法2 :

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

it ('should be visible when toggled', function() { 
    element.click(); 
    expect(element.find('span')).not.toHaveClass('ng-hide'); 
}); 

所以,我很好奇哪些方法和哪个方法最强大?

+1

我认为点击元素的单元测试就像是测试控制器方法量角器 – Appeiron

回答

1

我喜欢做的是创建像我这个虚拟示例一样的测试故事。因此,我想你只是没有在第二个例子中说明它,但如果你这样做,测试时总是使用describe enclosure,只是一个很好的做法。对于测试本身,我建议避免显式调用范围的方法$ digest(),尤其是对于您的测试而言,它似乎不是必需的。

不久,我会去的方法1.

+0

非常感谢您的答复。你能否通过一个例子说明你的测试与一个故事相结合的情况? –

+0

对不起,我现在只编辑,我在看一些虚拟的例子,因为我不能分享prod代码..但这解释了我在想什么短小,并为每个控制器添加一个故事像套 – desicne

1

我觉得第一种方法更“正确”,因为它不依赖于点击事件。我相信,如果你想测试一个元素的点击和它的效果,你应该使用量角器并且只对单元测试使用茉莉花。这样你将在单元测试和UI测试之间有一个很好的分离。

此外,它使测试更可维护。例如如果您决定在悬停时点击toggle而不是点击第二种方法,则您还必须更新测试。

+0

你假设你ment第一种方法是因为第二种方法执行'.click()'事情? –

+0

@JeanlucaScaljeri yap,我的意思是第一个。我修好了它。谢谢。 –

+0

为测试方法创建的单元测试返回并影响数据和行为驱动的测试(点击等)用于测试实际的用户交互。 – Appeiron

2

这里是你如何测试你的AngularJS指令:

describe('Directive: barFoo', function() { 
 
    var createElement, element, parentScope, directiveScope; 
 
    
 
    beforeEach(module('myApp')); 
 

 
    beforeEach(inject(function($injector) { 
 
    var $compile = $injector.get('$compile'); 
 
    var $rootScope = $injector.get('$rootScope'), 
 

 
    parentScope = $rootScope.$new(); 
 
    parentScope.paramXyz = ... <-- prepare whatever is expected from parent scope 
 

 
    createElement = function() { 
 
     element = $compile('<bar-foo></bar-foo>')(parentScope); 
 
     directiveScope = element.isolateScope(); 
 
     parentScope.$digest(); 
 
     $httpBackend.flush(); <-- if needed 
 
    }; 
 
    })); 
 

 

 
    it('should do XYZ', function() { 
 
    parentScope.xyz = ... <-- optionnal : adjust scope according to your test 
 
    createElement(); 
 

 
    expect(...) <-- whatever, examples : 
 

 
    var submitButton = element.find('button[type="submit"]'); 
 
    expect(submitButton).to.have.value('Validate'); 
 
    expect(submitButton).to.be.disabled; 
 
    submitButton.click(); 
 
    });

+0

这种方法或多或少与方法2相同。您能否提供一些为什么这比方法1更好的论证? –

+0

@JeanlucaScaljeri方法1)你必须手动创建控制器,并在方法2)中有一个额外的步骤。我建议的例子(取自我公司的实际测试)也显示了一个测试结构,它允许更容易的测试,在用'createElement()'实例化指令之前允许一些额外的inits *。还要注意父母和子女范围之间的明确分离。 – Offirmo

+0

我喜欢这种方法。我对测试指令很陌生。我想知道你如何确定一个特定的指令来测试?这是必要的吗? – Winnemucca

相关问题