2015-11-17 177 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

相關問題