Test-driven JavaScript mit Jasmine
Kommentare

Test-Doubles
Eine Anforderung an Unit Tests ist, dass sie möglichst unabhängig von anderen Tests und der Außenwelt ablaufen. Gerade in komplexeren Applikationen ist das nicht immer möglich. Eine Lösung

Test-Doubles

Eine Anforderung an Unit Tests ist, dass sie möglichst unabhängig von anderen Tests und der Außenwelt ablaufen. Gerade in komplexeren Applikationen ist das nicht immer möglich. Eine Lösung für dieses Problem bieten Spies. Sie ermöglichen es, die Aufrufe von Funktionen zu prüfen oder durch Fakes ganze Funktionen zu ersetzen. Dadurch können Tests von äußeren Einwirkungen unabhängig und so wesentlich stabiler gegen externe Einflüsse gemacht werden.

Der einfachste Einsatz von Spies ist die Prüfung, ob eine bestimmte Funktion beziehungsweise ob eine bestimmte Funktion mit bestimmten Parametern verwendet wurde. Zu diesem Zweck definiert man das Objekt und die Funktion, die man prüfen möchte. Man führt im Anschluss daran die Operation aus und hat dann die Möglichkeit, mithilfe des Matchers toHaveBeenCalled() zu testen, ob die entsprechende Funktion aufgerufen wurde. Mit toHaveBeenCalledWith() ist es möglich, zusätzlich einen oder mehrere Parameter zu spezifizieren, von denen man erwartet, dass sie mit dem Aufruf der Funktion verwendet wurden. Dieses Mittel dient dazu, dass man bei Aufrufen einer bestimmten Kette von Funktionen festlegen kann, dass eine Funktion wirklich und genau in der beabsichtigten Art und Weise verwendet wurde (Listing 1).

Listing 1
it('should call getBaseArea when getVolume is called', function() {
    var cube = new Cube(20);
    spyOn(cube, 'getBaseArea').andCallThrough();
    cube.getVolume();
    expect(cube.getBaseArea).toHaveBeenCalledWith(20, 20);
});

andCallThrough ist das Standardverhalten eines Spies und könnte daher einfach weggelassen werden. Um aber Missverständnissen oder eventuellen Fehlern vorzubeugen, sollte man diese explizite Schreibweise beibehalten. Will man jetzt aber das Verhalten einer abhängigen Funktion fixieren, um etwaige Unwägbarkeiten im Ablauf des Tests auszuschließen, verwendet man die Möglichkeit der Jasmine Spies, die überwachten Funktionen anzupassen. Ein Spy nimmt den Platz einer Funktion ein und reicht standardmäßig den Aufruf einfach an diese weiter, wirkt also wie ein Wrapper ohne weitere Funktionalität.

Mit der andReturn-Methode von spyOn ist es möglich, einen fixen Rückgabewert zu definieren (Listing 2). Durch diese Methode kann auf sehr leichte Art ein Stub erstellt werden. Ein Stub besitzt eine bestimmte Antwort, die er zur Verfügung stellt, wenn er aufgerufen wird. Ansonsten enthalten Stubs keine weitere Logik. Neben der Methode andReturn steht noch andThrow zur Verfügung, um das Verhalten von Quellcode beim Auftreten einer Exception zu simulieren. Ansonsten verhält sich diese Methode wie andReturn.

Listing 2
it('should calculate the volume, now with stub', function() {
    var cube = new Cube(20);
    spyOn(cube, 'getBaseArea').andReturn(800);
    expect(cube.getVolume()).toEqual(16000);
});

Interessant werden Spies vor allem, wenn es darum geht, Funktionalität zu ersetzen, also Funktionen zu mocken. Zu diesem Zweck bietet spyOn die Methode andCallFake. Sie erhält als Parameter eine Funktion, die statt der eigentlichen Funktion aufgerufen wird. Die Fake-Funktion erhält die gleichen Parameter wie die ursprüngliche Funktion und ist auch an den Objektkontext der Funktion gebunden, es steht also das korrekte this mit allen Properties zum Zeitpunkt des Aufrufs zur Verfügung. Im Test kann nun in Abhängigkeit des Objektstatus oder der Aufrufparameter das Verhalten der Funktion variiert und der gewünschte Wert zurückgegeben werden (Listing 3).

Listing 3
it('should have a volume of 2000 if the getArea Method is faked', function() {
    var cube = new Cube(20);
    spyOn(cube, 'getBaseArea').andCallFake(function(width, height) {
        if (this.height == 20 && this.width == 20) {
            return 100;
        }
        return false;
    });
    expect(cube.getVolume()).toEqual(2000);
});

Neben den vorgestellten Methoden bieten Spies noch ein paar Properties, die es ermöglichen, weitere Informationen über die Aufrufe der Spies zu erhalten. Das sind im Einzelnen callCount, die die Anzahl der Aufrufe des Spies enthält, und mostRecentCall.args beziehungsweise argsForCall[i] , um die Argumente für den letzten Aufruf beziehungsweise die Argumente des i-ten Aufrufs des Spies zu erhalten. Im Umgang mit Jasmine Spies gilt es zu beachten, dass sämtliche Spies nach jedem einzelnen Test wieder gelöscht werden. Ein Spy muss also entweder im Test selbst oder in der beforeEach-Funktion definiert werden, damit er für den Test zur Verfügung steht.


Themen der kommenden Seiten:

  • Asynchrone Tests
  • Ausführung im Browser
  • Integration in die IDE
  • Ausblick
Unsere Redaktion empfiehlt:

Relevante Beiträge

Meinungen zu diesem Beitrag

X
- Gib Deinen Standort ein -
- or -