Archiv der Kategorie: Unit Tests

Unit Test AngularJS directive mit templateUrl in VS und Chutzpah


Damit meine eigenen Direktiven übersichtlich bleiben, lege ich die Templates immer in einer extra HTML Datei ab und verwende entsprechend die “templateUrl” in meinen Direktiven.

Leider ist das Füllen des AngularJS Templatecaches mit Chutzpah ein klein wenig umständlicher als wenn man Karma und dem ng-html2js Präprozessor zum füllen des AngularJS Templatecaches verwendet. Da ich bei meiner Testumgebung aber nicht mehr Tools als notwendig einsetzen möchte und ich aktuell Chutzpah verwende, stelle ich im Folgenden einen möglichen Lösungsweg vor.

(Wie man ChutzPah in VS verwendet habe ich bereit hier erläutert.)

Als Grundlage verwende ich eine einfache Direktive mit TemplateUrl

angular.module("testTemplateDirective", [])
    .directive("testTemplate", function() {
        return {
            restrict: 'A',
            replace: true,
            templateUrl: 'ScriptsApp/directives/Templates/testTemplate.html'
        }
});

dazu gehört das folgende HTML Template “testTemplate.html” im Root Element muss eine eindeutige CSS Klasse hinterlegt werden die das Template identifiziert (leider notwendig für die Unit Tests).

<div class="row templateTestTemplate">
    <div class="col-lg-12">
        <h1>Tempalte Test</h1>
    </div>
</div>

Dazu muss man wissen das ChutzPah die Möglichkeit bietet neben den Referenzen zu den Script Dateien im Header des Tests ebenfalls den Pfad zu “templates” anzugeben mit einem “template” Tag.

/// <template path="../../MvcAngularJs1_3/ScriptsApp/directives/Templates/testTemplate.html" />
/// <reference path="../../mvcangularjs1_3/scripts/jquery-2.1.1.js" />
/// <reference path="../../mvcangularjs1_3/scripts/angular.js" />
/// <reference path="../../mvcangularjs1_3/scripts/angular-mocks.js" />
/// <reference path="../../mvcangularjs1_3/scriptsapp/directives/testtemplatedirective.js" />

... Unit Test

Der Komplette Inhalt des Templates wird dann in der HTML Testdatei eingefügt und kann über jQuery und unserer eindeutigen CSS Klasse ermittelt werden.

Da AngularJS immer erst prüft ob das Template bereits im TemplateCache enthalten ist, müssen wir unser Template nur noch manuell dem TemplateCache hinzufügen. Als Key wird hier die aufzurufende TemplateUrl verwendet. In meinem Beispiel wird der Key “ScriptsApp/directives/Templates/testTemplate.html” von AngularJS verwendet.

 var template = jQuery(".templateTestTemplate")[0].outerHTML;
 $templateCache.put("ScriptsApp/directives/Templates/testTemplate.html", template);

Wenn das Template einmal dem TemplateCache hinzugefügt wurde, ist der Rest des Unit Tests für Direktiven so wie jeder andere Unit Tests für Direktiven.

ACHTUNG: Der Unit Tests ist nur erfolgreich, wenn der Test mit ChutzPah ausgeführt wird. Wenn der Unit Test mit Resharper ausgeführt wird, dann schlägt der Unit Test fehl, denn Resharper kennt das “template” Tag nicht und fügt damit auch keinen HTML Code in der Testdatei ein wie ChutzPah.

Der komplette Test sieht dann folgendermaßen aus

/// <template path="../../MvcAngularJs1_3/ScriptsApp/directives/Templates/testTemplate.html" />
/// <reference path="../../mvcangularjs1_3/scripts/jquery-2.1.1.js" />
/// <reference path="../../mvcangularjs1_3/scripts/angular.js" />
/// <reference path="../../mvcangularjs1_3/scripts/angular-mocks.js" />
/// <reference path="../../mvcangularjs1_3/scriptsapp/directives/testtemplatedirective.js" />

var siteRoot = "";

angular.module("app.testtmplate", ["testTemplateDirective"]);

describe("Unit Tests für die Direktive 'testTemplateDirective' ", function() {
    var $rootScope, $compile;

   beforeEach(function() {
        //Unsere Main App laden
        module('app.testtmplate');
        inject(function(_$rootScope_, _$compile_) {
            $rootScope = _$rootScope_;
            $compile = _$compile_;
        });
    });

    describe('Tests für Direktive "testTemplateDirective"', function () {
        beforeEach(function () {
            inject(function ($templateCache) {
                //mit jQuery unseren HTML Code inkl. des Selectors ermitteln.
                var template = jQuery(".templateTestTemplate")[0].outerHTML;
                $templateCache.put("ScriptsApp/directives/Templates/testTemplate.html", template);
            });
        });

        it('Es wurde ein H1 mit dem Text "Template Test" angelegt', function () {
            var element = $compile("<div><div test-template></div>")($rootScope);
            $rootScope.$digest();

            expect(element.html()).toContain("<h1>Tempalte Test</h1>");
            expect(element.find("h1").length).toBe(1);
        });
    });
})

JavaScript Unit Tests mit Jasmine und Visual Studio (Resharper oder Cutzpah)


Bisher habe ich Unit Tests nur für .Net (C#) geschrieben, inzwischen nimmt aber auch der Clientseitige Code in Webanwendungen durch Frameworks wie AngularJS immer bessere Strukturen an, die sich ebenfalls sehr gut testen lassen. Außerdem gibt es sehr gute Plugins für Visual Studio (VS) die einem das Ausführen von JavaScript Unit Tests direkt im VS sehr einfach machen, hier war ich positiv überrascht, denn ich hatte mir das Einrichten schwerer vorgestellt.

Als Testframework verwende ich “Jasmine” mit dem sich die JavaScript Unit Tests sehr strukturiert aufbauen lassen. Mit Jasmin lässt sich z.B. testen ob die folgende JavaScript Funktion “calc” (Datei: custom.js) auch beide Zahlen addiert:

function calc() {
    return {
        add: function(a,b) {
            return a + b;
        }
    }
}

Der passende Unit Test mit Jasmine sieht z.B. folgendermaßen aus:

///<reference path="jasmine.js" />
///<reference path="customjs.js" />
describe('Testen der Calc Funktion', function() {
     var calculator;
    //Wird vor jedem Test ausgeführt
    beforeEach(function() {
        calculator = new calc();
    });

    it('2 plus 4 ergibt 6', function() {
        var result = calculator.add(2, 4);
        expect(result).toBe(6);
    });
});

Dabei kann man mit Jasmine die Test sehr einfach strukturieren über die “describe” und “it” Funktionen. Bei beiden Funktionen wird erst ein String übergeben, bei “describe” handelt es sich um die Beschreibung der Kategorisierung der darunterliegenden Tests und bei “it”  um die direkte Beschreibung eines Tests. Ich verweise an dieser Stelle aber am einfachsten auf die Dokumentation von Jasmine 2.2, denn diese ist hervorragend umgesetzt und zeigt alle Funktionen von Jasmine an kurzen und einfachen Beispielen.

Vor dem jeweiligen Test muss noch die Referenz auf die Dateien angegeben werden die für diesen Test benötigt werden. Hier am einfachsten die Daten per Drag und Drop in die Testdatei ziehen und VS legt automatisch die Referenzen an. Wichtig ist außerdem die richtige Reihenfolge der Referenzen. Bei mir habe ich hin und wieder das Problem das die Referenzen absolut eingetragen werden und nicht relativ, wenn hier evtl. jemand die Lösung kennt das der Pfad immer relativ eingetragen wird, würde ich mich über einen Hinweis freuen.

Damit man die JavaScript Unit Tests auch im Visual Studio ausführen kann und die Ergebnisse z.B. auch im Testexplorer angezeigt werden, kenne ich bisher zwei verschiedene Plugins die beide auch unabhängig voneinander funktionieren.

1. Unit Tests mit Resharper

Resharper unterstützt von Haus aus Unit Tests mit dem Jasmine Framework. Dafür muss man nur unter “RESHARPER => Options” die passenden “Unit Testing” Einstellungen vornehmen.

image

Da ich bei mir Jasmine verwende, ist bei mir nur Jasmine ausgewählt. Wenn man nicht möchte das beim Ausführen der Tests immer ein Browserfenster geöffnet wird, kann man PhantomJS verwenden und einfach den Pfad zur “phantomjs.exe” angegeben. Damit werden die Tests dann im Hintergrund ausgeführt ohne zusätzliches Browserfenster.

Hinweis: Bei Resharper ist über dem Test kein Referenz link auf die “Jasmine.js” Datei notwendig. Ich füge ihn aber für IntelliSense immer ein.

Das gute an Resharper ist, das dieser die Tests direkt in der JavaScript Datei erkennt und genau wie bei .NET Tests die Testicons direkt daneben anzeigt.

image

Auch der Testexplorer von Resharper funktioniert mit den JavaScript Unit Tests problemlos und zeigt an welche Tests erfolgreich bzw. fehlgeschlagen sind.

image

2. Unit Tests mit Chutzpah

Bei Chutzpah handelt es sich ebenfalls um eine VS Extension, die aber in diesem Fall kostenlos ist und über “TOOLS => Extensions und Updates…” installiert werden kann.

image

Ich habe bei mir beide Chutzpah Erweiterungen installiert. Damit bekommt man zum einen alle JavaScript Unit Tests auch im VS enthaltenen Testexplorer angezeigt und man kann die Tests von hier aus auch starten.

image

Mit der Context Menü Erweiterung kann man auch direkt über die rechte Maustaste den gerade ausgewählten Test oder für eine ganze Datei die Tests ausführen lassen.

image

Des weiteren ist es möglich den Test im Browser anzuzeigen und direkt im Browser zu debuggen, denn hier wird ein Pfad zu einer lokal erstellten HTML Datei geöffnet die alle wichtigen Verweise und die JavaScript Testfälle enthält. Was ich persönlich sehr cool finde, wenn man doch einmal nicht versteht warum der Test nicht funktioniert kann man hier noch einmal im Detail die aktuellen Objekte überprüfen.

image

Außerdem soll es mit Chutzpah auch möglich sein die JavaScript Unit Tests auf dem Build Server auszuführen, hier habe ich bisher aber keine Erfahrungen sammeln können, aber die beiden folgenden Links helfen euch evtl. weiter:

http://blogs.msdn.com/b/visualstudioalm/archive/2012/07/09/javascript-unit-tests-on-team-foundation-service-with-chutzpah.aspx

http://www.rosher.co.uk/post/Unit-Testing-AngularJS-with-Jasmine-Chutzpah-and-Visual-Studio

Wenn jemand weiß wie man die JavaScript Tests in VS automatisch ausführen lassen kann wenn sich an den Tests oder den Codefiles etwas ändert würde ich mich ebenfalls über einen Link freuen.