2015-11-17 10 views
8

Unit-Test eine Winkel-Richtlinie ist nicht sehr schwer, aber ich fand heraus, dass es verschiedene Möglichkeiten, es zu tun.Wie Unit-Test eine Winkel-Richtlinie

Für den Zweck dieser Stelle, können Sie die folgende Direktive

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

Jetzt nehme ich dieses

Methode 1 von zwei Möglichkeiten, um Unit-Test denken kann:

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(); 
    }); 
}); 

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

Also, ich bin gespannt, was die Vor- und Nachteile beider Methoden und welche ist am robustesten?

+1

Ich gehe davon aus, dass in Unit-Tests auf Element klicken ist wie Test-Controller Methoden in Winkelmesser – Appeiron

Antwort

1

Was ich tun möchte, ist Geschichten meines Tests wie dieses Dummy-Beispiel zu erstellen. So

'use strict'; 

describe('app controller', function() { 

    var scope; 

    ... 

    beforeEach(angular.mock.module('MyModule')); 

    it('should have properties defined', function() { 

    expect(scope.user).toEqual(user); 
    ...  

    }); 

    it('should have getFaqUrl method', function() { 

    expect(scope.getFaqUrl).toEqual(refdataService.getFaqUrl); 

    }); 

    it('should signout and delete user data from local storage', function() { 

    ... 

    }); 

}); 

Ich denke, man einfach nicht in zweiten Beispiel angegeben hätte, aber im Fall haben Sie verwenden Gehäuse immer beschreiben, wenn die Prüfung, nur eine gute Praxis.

Was den Test selbst betrifft, würde ich Ihnen raten, die Methode zu vermeiden, bei der Sie explizit den Bereich $ digest() aufrufen, vor allem, weil dies für den Zweck Ihres Tests nicht notwendig erscheint.

Kurz, würde ich für Verfahren gehen 1.

+0

Vielen Dank für die Antwort. Könnten Sie Ihren Beitrag mit einem Beispiel aktualisieren, wie Ihr Test in Kombination mit einer Geschichte aussieht? –

+0

Sorry, ich habe nur bearbeitet, ich habe in einem Dummy-Beispiel gesucht, wie ich Prod-Code nicht teilen kann .. aber das erkläre, was ich über Shorty dachte, und für jeden Controller, fügen Sie eine Geschichte wie Sätze – desicne

1

Ich finde die erste Methode mehr „richtig“, weil es auf einem Klickereignis abhängig tut. Ich glaube, wenn Sie das Klicken eines Elements und dessen Auswirkungen testen möchten, sollten Sie Winkelmesser verwenden und Jasmin nur für Komponententests verwenden. Auf diese Weise haben Sie eine gute Trennung zwischen den Komponententests und den UI-Tests.

Auch macht es den Test mehr Haupttabelle. z.B. Wenn Sie sich entscheiden, toggle auf Hover statt auf Klick in der zweiten Methode auslösen, müssen Sie auch die Tests zu aktualisieren.

+0

Sie übernehmen Sie ment die erste Methode, weil die zweite Methode das '.click()' Ding macht? –

+0

@JeanlucaScaljeri Yap, ich meinte die erste. Ich habe es repariert. Danke. –

+0

Komponententests, die für Testmethoden erstellt wurden, Rückmeldungen und Auswirkungen auf Daten und verhaltensorientierte Tests (Klicks usw.) werden zum Testen tatsächlicher Benutzerinteraktionen verwendet. – Appeiron

2

Hier ist, wie Sie Ihre AngularJS Richtlinie testen:

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

Dieser Ansatz entspricht mehr oder weniger der Methode 2. Können Sie einige Argumente dafür liefern, warum dies besser ist als Methode 1? –

+0

@JeanlucaScaljeri in Methode 1) müssen Sie den Controller manuell erstellen und in Methode 2) haben Sie einen zusätzlichen Schritt.Das Beispiel, das ich vorschlage (aus unseren tatsächlichen Tests in meiner Firma), zeigt auch eine Teststruktur, die ein einfacheres Testen ermöglicht, indem einige zusätzliche Eingaben erlaubt werden, bevor die Anweisung mit createElement() instanziiert wird. Beachten Sie auch die klare Trennung zwischen dem übergeordneten und dem untergeordneten Bereich. – Offirmo

+0

Ich mag diesen Ansatz. Ich bin neu in Testing Direktiven. Ich frage mich, wie Sie eine bestimmte zu testende Richtlinie identifizieren? Ist das notwendig? – Winnemucca