Unit-Tests

Unit-Tests oder Komponententests dienen der Überprüfung von funktionalen Einheiten. Sie sollen gezielt die Funktionalität der Komponenten testen, isoliert von anderen Komponenten. Aus diesem Grund besitzen sie eine deutlich geringere Komplexität im Vergleich zu Integrations- bzw. Systemtests, welche erheblich mehr Entwicklungsaufwand erfordern.

Mit dem 'Unit-Test' Knoten können Unit-Tests mit Hilfe des JUnit-Frameworks als Teil eines QF-Test Testlaufs ausgeführt werden. Sowohl der Report als auch das Protokoll zeigen deren Ergebnisse an. Die Einbindung von QF-Test Testsuiten in bestehende JUnit-Tests wird in Abschnitt 27.5 beschrieben.

Der 'Unit-Test' Knoten kann Tests aus zwei unterschiedlichen Quellen starten. Hierbei werden die Parameter des Knotens dynamisch an den Anwendungsfall angepasst. Es können Java-Klassen angegeben werden, die JUnit-Testfälle enthalten, oder Unit-Test-Skripte mit QF-Test geschrieben werden. Dieses Kapitel erläutert die unterschiedlichen Möglichkeiten.

Für die Ausführung der JUnit-Tests wird das JUnit 5 Framework verwendet. Dieses ermöglicht es einerseits JUnit 5 Tests mit Hilfe der JUnit Jupiter Engine auszuführen. Andererseite kann die JUnit Vintage Engine sowohl JUnit 4 als auch JUnit 3 Tests ausführen. Mit JUnit 5 ist es möglich parametrisierte Tests zu schreiben, Tests innerhalb von Klassen einzubetten und den Reportnamen des Tests zu ändern.

Java-Klassen als Quelle für Unit-Tests

Es ist möglich Unit-Tests aus geladenen Jar-Ordnern und Class-Dateien auszuführen. Es können aber auch Tests ausgeführt werden, die bereits mit dem Start des SUTs geladen wurden. QF-Test führt dabei die angegebenen 'Test-Klassen' als Testschritte aus. Das folgende Beispiel soll den Aufbau eines Unit-Tests mit Java-Klassen verdeutlichen.

Beispiel eines Unit-Test Knotens Java-Klassen
Abbildung 12.1:  Unit-Test-Knoten mit Java-Klassen
package de.qfs.test;

import org.junit.Assert;
import org.junit.Test;

public class StringTest {

    @Test
    public void testubstring() {
        String s = new String("Langer Text");
        s = s.substring(7, 11);
        assert("Text".equals(s));
    }

    @Test
    public void testReplace() {
        String s = new String("Beispiel");
        s = s.replace('e', 'i');
        Assert.assertEquals("Biispiil", s);
    }
}
Beispiel 12.1:  Code der Java-Unit-Test-Klasse

Die Klasse de.qfs.test.StringTest muss sich im unittests.jar befinden. Der Pfad zu dieser Jar-Datei wird unter 'Classpath' angegeben. Dieser Pfad wird relativ zum Verzeichnis der aktuellen Suite ermittelt. In diesem Beispiel liegt die jar-Datei direkt im Verzeichnis der Testsuite.

JUnit-Test-Klassen sind Java-Klassen, deren Methoden die @Test-Annotation besitzen. Der 'Unit-Test' Knoten führt alle Klassen aus, die unter 'Test-Klassen' angegeben sind. Deshalb kann ein 'Unit-Test' Knoten auch mehrere Test-Klassen ausführen.

Grundlagen der Test-Skripte

Die zweite Möglichkeit, die Unit-Test Knoten bieten, ist den Unit-Test direkt im Knoten zu kodieren. Hierfür können die in QF-Test vorhanden Skriptsprachen genutzt werden. Groovy ist dazu am besten geeignet, denn es ermöglicht die Verwendung von Java-Annotationen. Das Framework hierfür ist JUnit.

Groovy Unit-Tests

@BeforeClass
static void onbefore(){
    println("Vorbereitung")
}

@Test(expected=IndexOutOfBoundsException.class)
void indexOutOfBoundsAccess() {
    def numbers = [1,2,3,4]
    numbers.get(4)
}

@Test
void noFailure() {
    assert true
}
Beispiel 12.2:  Unit-Test-Skript mit Groovy

In Groovy werden die für JUnit 4 erforderlichen Klassen automatisch importiert. Und wie in Java werden alle Tests mit der @Test-Annotation ausgeführt. Der expected Parameter der @Test-Annotation erlaubt es, erwartete Exceptions zu ignorieren. Die Methode, welche mit der @BeforeClass-Annotation gekennzeichnet ist, wird einmal vor der Ausführung der Test-Methoden ausgeführt.

Jython Unit-Tests

def setUp(self):
    print "Vorbereitung"

def testMathCeil(self):
    import math
    self.assertEqual(2, math.ceil(1.01))
    self.assertEqual(1, math.ceil(0.5))
    self.assertEqual(0, math.ceil(-0.5))
    self.assertEqual(-1, math.ceil(-1.1))

def testMultiplication(self):
    self.assertAlmostEqual(0.3, 0.1 * 3)
    
Beispiel 12.3:  Unit-Test Skript mit Jython

Da in Jython keine Java-Annotationen verwendet werden können, werden die Skripte als JUnit-3-Tests ausgeführt. Alle Funktionen, die mit dem Schlüsselwort test beginnen, werden als Checks ausgeführt. Die Methoden müssen den Parameter self besitzen, da diese von einer Klasse umschlossen werden. Die setUp-Methode wird vor Beginn der Tests ausgeführt.

JavaScript Unit-Test

setUp(){
    print("Vorbereitung");
}
tearDown() {
    print("Nachbereitung");
}
testUpperCase(){
    let s = "text";
    assertEquals("TEXT", s.toUpperCase());
}
testOk() {
    assertTrue(true);
}
Beispiel 12.4:  Unit-Test Skript mit JavaScript

Da auch JavaScript keine Java-Annotationen unterstützt, können nur JUnit-3 Tests (vgl. Abschnitt 12.2.2) ausgeführt werden. Wie in Jython werden alle Funktionen, die mit dem Schlüsselwort test beginnen, als Checks ausgeführt.

Injections

Es ist möglich, den 'Unit-Test' Knoten für sogenannte 'LiveTests' zu nutzen. QF-Test führt die Unit-Tests hierbei in einem laufenden SUT aus. Um in den JUnit-Test-Klassen Objekte wie Komponenten, QF-Test Variablen oder WebDriver-Objekte verwenden zu können, müssen diese in den Code 'injiziert' werden.

Komponenten in den Unit-Tests verwenden

import static org.junit.Assert.*;
import javax.swing.JComponent;
import org.junit.Test;

public class ComponentTest
{

    /** The component to test in this unit test */
    static JComponent component;

    /** Expected value */
    static String accessibleName;

    @Test
    public void accessibleNameIsCorrect()
    {
        /** component and accessible name are injected at run-time */
        final String currentName =
            component.getAccessibleContext().getAccessibleName();
        assertEquals(accessibleName,currentName);
    }
}
Beispiel 12.5:  Java-Unit-Test-Klasse

Beispiel eines Unit-Test Knotens mit Injections
Abbildung 12.2:  Beispiel eines 'Unit-Test' Knotens mit Injections

In diesem Beispiel werden gleich zwei Objekte in die Unit-Tests übertragen. Eine Komponente und eine QF-Test Variable. Der Parameter 'Feld' der Injection entspricht hier dem Namen des Felds static JComponent component; der Java-Klasse. Das Java-Feld muss hierfür static sein.

WebDriver-Injections

import static org.junit.Assert.*;
import org.junit.Test;
import org.openqa.selenium.WebDriver;

public class WebdriverTest
{
    /** The driver of the window currently opened by QF-Test. */
    static WebDriver driver;

    @Test
    public void urlIsCorrectedLoaded()
    {
        // driver is injected at run-time
        final String currentUrl = driver.getCurrentUrl();
        assertEquals("http://www.example.com", currentUrl);
    }

}
Beispiel 12.6:  Java-Unit-Test mit WebDriver-Injections

Beispiel eines Unit-Test-Knotens mit Injections
Abbildung 12.3:  Beispiel eines 'Unit-Test'-Knotens mit WebDriver-Injections

Dieses Beispiel zeigt wie ein WebDriver-Objekt in die Java-Klasse übertragen wird. QF-Test ermittelt den Wert der WebDriver-Injection anhand des angegebenen Clients, falls kein expliziter Wert gesetzt ist.

Unit-Tests im Report

Der große Vorteil des 'Unit-Test' Knotens ist, dass dieser im HTML-Report erscheint. Die Unit-Tests werden als Testfälle interpretiert. Damit diese korrekt im Report erscheinen, muss ein Testfall ausgeführt werden, in welchem der Unit-Test-Knoten enthalten ist.

Beispiel eines Unit-Test Reports
Abbildung 12.4:  Unit-Test Report