StartseiteSitemapDownloadsHilfeImpressum Chat


Startseite

JUnit−Beispiel

Um überhaupt etwas mit JUnit auf Korrektheit testen bzw. prüfen zu können, benötigt man zunächst eine spezifizierte Klasse. Hier ist die zu testende Klasse ein sehr einfaches Perzeptron aus dem Bereich der künstlichen Intelligenz.

Perceptron.java (eine zu testende Klasse)

/**
 * Repräsentiert ein simples Perceptron (Neuron).
 */

public class Perceptron {

    /**
     * Der Schwellwert.
     */

    public double threshold;

    /**
     * Der Gewichtsvektor.
     */

    private Vector weight;

    /**
     * Instantiiert ein Perceptron mit einem Gewichtsvektor.
     * Der Gewichtsvektor des Perceptrons wird auf die Länge 1 normiert.
     * @param weight Der Gewichtsvektor.
     */

    public Perceptron(Vector weight) {
        this.threshold = 0.70;
        this.weight = weight.getNormalized();
    }

    /**
     * Instantiiert ein Perceptron mit Gewichtswerte.
     * @param weights Die Gewichtswerte.
     */

    public Perceptron(double[] weights) {
        this(new Vector(weights));
    }

    /**
     * Das Perceptron wird aktiviert mit gegebenem Input-Vektor
     * und feuert, wenn der Input etwa in dieselbe Richtung
     * wie der Gewichtsvektor zeigt.
     * Die Abweichung, die erlaubt ist, wird vom Schwellwert
     * threshold festgelegt.
     * @param input Der Input-Vektor.
     * @return Ungleich 0.0, wenn das Perceptron feuert.
     */

    public double activate(Vector input) {
        Vector normedInput = input.getNormalized();
        double result = Vector.dotProduct(normedInput, this.weight);
        if (threshold < result) {
            return result;
        } else {
            return 0.0;
        }
    }
}
Da nun eine Klasse vorliegt, kann auch eine dazugehörige Testklasse (TestCase) erstellt werden. Die Testbasisklasse TestCase stellt weitere Methoden zum Überschreiben zur Verfügung. Vor jeder einzelnen Testmethode wird zum Beispiel stets setUp() und nach Ausführung tearDown() ausgeführt. So wird dem Programmierer die Möglichkeit gegeben, vor und nach Ausführung einer Testmethode den Objektzustand der Testklasse zu restaurieren.
Eine wichtige Klasse, die das JUnit-Framework zur Verfügung stellt, heißt Assert. Mit ihr kann man recht einfach Vergleiche verschiedener Objekte durchführen. Scheitert ein Assert-Vergleich, so wird die dazugehörige Testmethode mit failed gekennzeichnet.

TestPerceptron.java

import junit.framework.Assert;
import junit.framework.TestCase;

/**
 * Diese Klasse prüft die Perceptron-Klasse auf Fehler.
 */

public class TestPerceptron extends TestCase {

    // Der maximal tolerierbare Fehler beim Double-Vergleich.
    private static double DELTA = 0.000000000001;

    // Vier Testexemplare, diese werden in setUp instantiiert.
    private Perceptron p1;
    private Perceptron p2;
    private Vector v1;
    private Vector v2;

    /**
     * Instantiiert die Testexemplare für jede einzelne Testmethode
     * erneut. So kann gewährleistet werden, dass die Testmethoden
     * unabhängig voneinander sind.
     */

    protected void setUp() throws Exception {
        super.setUp();
        this.p1 = new Perceptron(new double[] {1.0, 0.0});
        this.p2 = new Perceptron(new double[] {0.0, 1.0});
        this.v1 = new Vector(new double[] {8.0, 0.0});
        this.v2 = new Vector(new double[] {0.0, 2.0});
    }

    /**
     * Hauptprogramm führt den Testfall auf Konsolenebene aus.
     */

    public static void main(String[] args) {
        junit.textui.TestRunner.run(TestPerceptron.class);
    }

    /**
     * Prüft die Methode activate der Klasse Perceptron auf Fehler.
     */

    public void testActivate() {
        Assert.assertEquals(1.0, this.p1.activate(this.v1), DELTA);
        Assert.assertEquals(0.0, this.p1.activate(this.v2), DELTA);
        Assert.assertEquals(0.0, this.p2.activate(this.v1), DELTA);
        Assert.assertEquals(1.0, this.p2.activate(this.v2), DELTA);
        // Selbstkritischer Kommentar!
        System.out.print("[Grenzfälle fehlen]");
    }
}
Schlechte Unit−Tests tragen überhaupt nicht zur Verbesserung des Produktes bei. Deshalb muss der Tester sehr selbstkritisch vorgehen. Wenn — aus welchen Gründen auch immer — die Implementierung eines Tests unvollständig ausfallen sollte, muss er das melden, wie hier durch eine System.out−Meldung. Sonst bleiben vermeidbare Fehler möglicherweise für immer unentdeckt.
Um die Klasse Perceptron verifizieren zu können, muss nur noch TestPerceptron ausgeführt werden.

java TestPerceptron

.[Grenzfälle fehlen]
Time: 0,02

OK (1 test)
Da aber die Klasse Perceptron eine Vektorklasse kapselt, so muss auch diese getestet werden. Im Folgenden wird zunächst die Klasse Vector gezeigt.

Vector.java (eine zu testende Klasse)

/**
 * Repräsentiert einen n-dimensionalen Vektor aus der Mathematik.
 * Der Grundkörper ist die Fließkommazahl double.
 */

public class Vector {

    /**
     * Die Komponenten des Vektors.
     */

    private double[] scalars;

    /**
     * Instantiiert einen Vektor mit angegebener Dimension.
     * Die Komponenten des Vektors werden mit 0.0 initialisiert.
     * @param dimension Die Dimension.
     */

    public Vector(int dimension) {
        this.scalars = new double[Math.max(1, dimension)];
        for (int i = 0; i < this.scalars.length; i++) {
            this.scalars[i] = 0.0;
        }
    }

    /**
     * Instantiiert einen Vektor mit gegebenen Skalarwerten.
     * @param scalars Die Skalarwerte.
     */

    public Vector(double[] scalars) {
        this(scalars.length);
        this.setScalars(scalars);
    }

    /**
     * Instantiiert einen Vektor, indem ein anderer Vektor kopiert wird.
     * @param vector Der andere Vektor.
     */

    public Vector(Vector vector) {
        this(vector.getDimension());
        this.setScalars(vector.getScalars());
    }

    /**
     * Gibt eine Kopie (Klon) des Vektors zurück.
     * @return Der Klon.
     */

    public Vector copy() {
        return new Vector(this);
    }

    /**
     * Gibt die Dimension des Vektors zurück.
     * @return Die Dimension.
     */

    public int getDimension() {
        return this.scalars.length;
    }

    /**
     * Gibt die Skalarwerte des Vektors als Array zurück.
     * @return Die Skalarwerte als Array.
     */

    public double[] getScalars() {
        return this.scalars;
    }

    /**
     * Setzt die Komponenten des Vektors auf gegebene Skalarwerte.
     * Konflikte mit unterschiedlicher Dimension entstehen nicht.
     * @param scalars Die Skalarwerte.
     */

    public void setScalars(double[] scalars) {
        int count = Math.min(this.getDimension(), scalars.length);
        for (int i = 0; i < count; i++) {
            this.scalars[i] = scalars[i];
        }
    }

    /**
     * Setzt die i-te Komponente auf gegebenen Skalarwert.
     * @param index Der Index für die i-te Komponente.
     * @param scalar Der Skalarwert.
     */

    public void setScalar(int index, double scalar) {
        if ((0 <= index) && (index < this.getDimension())) {
            this.scalars[index] = scalar;
        }
    }

    /**
     * Berechnet das Skalarprodukt zweier Vektoren.
     * Es können zwei Vektoren unterschiedlicher Dimension
     * verwendet werden. Die Berechnung richtet sich nach der
     * kleineren Dimension.
     * @param v1 Vektor 1.
     * @param v2 Vektor 2.
     * @return Das Skalarprodukt.
     */

    public static double dotProduct(Vector v1, Vector v2) {
        double result = 0;
        int count = Math.min(v1.getDimension(), v2.getDimension());
        for (int i = 0; i < count; i++) {
            result += v1.getScalars()[i] * v2.getScalars()[i];
        }
        return result;
    }

    /**
     * Gibt die Länge des Vektors zurück.
     * @return Die Länge des Vektors.
     */

    public double getLength() {
        return Math.sqrt(dotProduct(this, this));
    }

    /**
     * Normalisiert den Vektor auf die Länge 1.
     * Ist der Vektor ein Nullvektor, so bleibt er ein Nullvektor.
     */

    public void normalize() {
        double length = this.getLength();
        if (length != 0.0) {
            for (int i = 0; i < this.getDimension(); i++) {
                this.scalars[i] /= length;
            }
        }
    }

    /**
     * Gibt den normalisierten Vektor der Länge 1 zurück.
     * Ist der Vektor ein Nullvektor, so wird ein Nullvektor zurückgegeben.
     * @return Der normalisierte Vektor.
     */

    public Vector getNormalized() {
        Vector result = this.copy();
        result.normalize();
        return result;
    }
}
Der Test der Vektorklasse geschieht analog zum Test der Perzeptronklasse.

TestVector.java

import junit.framework.Assert;
import junit.framework.TestCase;

/**
 * Diese Klasse prüft die Vector-Klasse auf Fehler.
 */

public class TestVector extends TestCase {

    // Der maximal tolerierbare Fehler beim Double-Vergleich.
    private static double DELTA = 0.000000000001;

    // Drei Testexemplare, diese werden in setUp instantiiert.
    private Vector vector1;
    private Vector vector2;
    private Vector vector3;

    /**
     * Instantiiert die Testexemplare für jede einzelne Testmethode
     * erneut. So kann gewährleistet werden, dass die Testmethoden
     * unabhängig voneinander sind.
     */

    protected void setUp() throws Exception {
        super.setUp();

        this.vector1 = new Vector(-1);
        this.vector2 = new Vector(new double[] {1.0, 0.0, 1.0, 0.0});
        this.vector3 = new Vector(new double[] {2.0, 0.0, 1.0, 3.0});
    }

    /**
     * Hauptprogramm führt den Testfall auf Konsolenebene aus.
     */

    public static void main(String[] arguments) {
        junit.textui.TestRunner.run(TestVector.class);
    }

    /**
     * Prüft die Methode copy der Klasse Vector auf Fehler.
     */

    public void testCopy() {
        Vector v1 = this.vector1.copy();
        Assert.assertEquals(this.vector1.getScalars()[0],
                v1.getScalars()[0], DELTA);
        Vector v2 = this.vector2.copy();
        Assert.assertEquals(this.vector2.getScalars()[0],
                v2.getScalars()[0], DELTA);
        Assert.assertEquals(this.vector2.getScalars()[1],
                v2.getScalars()[1], DELTA);
        Assert.assertEquals(this.vector2.getScalars()[2],
                v2.getScalars()[2], DELTA);
        Assert.assertEquals(this.vector2.getScalars()[3],
                v2.getScalars()[3], DELTA);
        Vector v3 = this.vector3.copy();
        Assert.assertEquals(this.vector3.getScalars()[0],
                v3.getScalars()[0], DELTA);
        Assert.assertEquals(this.vector3.getScalars()[1],
                v3.getScalars()[1], DELTA);
        Assert.assertEquals(this.vector3.getScalars()[2],
                v3.getScalars()[2], DELTA);
        Assert.assertEquals(this.vector3.getScalars()[3],
                v3.getScalars()[3], DELTA);
    }

    /**
     * Prüft die Methode getDimension der Klasse Vector.
     */

    public void testGetDimension() {
        Assert.assertEquals(1, this.vector1.getDimension());
        Assert.assertEquals(4, this.vector2.getDimension());
        Assert.assertEquals(4, this.vector3.getDimension());
    }

    /**
     * Prüft die Methode getScalars der Klasse Vector auf Fehler.
     */

    public void testGetScalars() {
        Assert.assertEquals(1.0, this.vector2.getScalars()[0], DELTA);
        Assert.assertEquals(0.0, this.vector2.getScalars()[1], DELTA);
        Assert.assertEquals(1.0, this.vector2.getScalars()[2], DELTA);
        Assert.assertEquals(0.0, this.vector2.getScalars()[3], DELTA);
        Assert.assertEquals(2.0, this.vector3.getScalars()[0], DELTA);
        Assert.assertEquals(0.0, this.vector3.getScalars()[1], DELTA);
        Assert.assertEquals(1.0, this.vector3.getScalars()[2], DELTA);
        Assert.assertEquals(3.0, this.vector3.getScalars()[3], DELTA);
    }

    /**
     * Prüft die Methode setScalars der Klasse Vector auf Fehler.
     */

    public void testSetScalars() {
        this.vector1.setScalars(new double[] {1.0, 2.0, 3.0, 4.0});
        Assert.assertEquals(1, this.vector1.getDimension());
        Assert.assertEquals(1.0, this.vector1.getScalars()[0], DELTA);
        this.vector2.setScalars(new double[] {1.0, 2.0, 3.0, 4.0});
        Assert.assertEquals(4, this.vector2.getDimension());
        Assert.assertEquals(1.0, this.vector2.getScalars()[0], DELTA);
        Assert.assertEquals(2.0, this.vector2.getScalars()[1], DELTA);
        Assert.assertEquals(3.0, this.vector2.getScalars()[2], DELTA);
        Assert.assertEquals(4.0, this.vector2.getScalars()[3], DELTA);
        this.vector3.setScalars(new double[] {1.0, 2.0, 3.0, 4.0});
        Assert.assertEquals(4, this.vector3.getDimension());
        Assert.assertEquals(1.0, this.vector3.getScalars()[0], DELTA);
        Assert.assertEquals(2.0, this.vector3.getScalars()[1], DELTA);
        Assert.assertEquals(3.0, this.vector3.getScalars()[2], DELTA);
        Assert.assertEquals(4.0, this.vector3.getScalars()[3], DELTA);
    }

    /**
     * Prüft die Methode setScalar der Klasse Vector auf Fehler.
     */

    public void testSetScalar() {
        this.vector2.setScalar(-1, 2.75);
        this.vector2.setScalar(4, 2.75);
        Assert.assertEquals(1.0, this.vector2.getScalars()[0], DELTA);
        Assert.assertEquals(0.0, this.vector2.getScalars()[1], DELTA);
        Assert.assertEquals(1.0, this.vector2.getScalars()[2], DELTA);
        Assert.assertEquals(0.0, this.vector2.getScalars()[3], DELTA);
        this.vector2.setScalar(0, 0.75);
        this.vector2.setScalar(1, 1.75);
        this.vector2.setScalar(2, 2.75);
        this.vector2.setScalar(3, 3.75);
        Assert.assertEquals(0.75, this.vector2.getScalars()[0], DELTA);
        Assert.assertEquals(1.75, this.vector2.getScalars()[1], DELTA);
        Assert.assertEquals(2.75, this.vector2.getScalars()[2], DELTA);
        Assert.assertEquals(3.75, this.vector2.getScalars()[3], DELTA);
    }

    /**
     * Prüft die Methode dotProduct der Klasse Vector auf Fehler.
     */

    public void testDotProduct() {
        Assert.assertEquals(0.0,
                Vector.dotProduct(this.vector1, this.vector1), DELTA);
        Assert.assertEquals(0.0,
                Vector.dotProduct(this.vector1, this.vector2), DELTA);
        Assert.assertEquals(0.0,
                Vector.dotProduct(this.vector1, this.vector3), DELTA);
        Assert.assertEquals(0.0,
                Vector.dotProduct(this.vector3, this.vector1), DELTA);
        Assert.assertEquals(2.0,
                Vector.dotProduct(this.vector2, this.vector2), DELTA);
        Assert.assertEquals(4.0 + 1.0 + 9.0,
                Vector.dotProduct(this.vector3, this.vector3), DELTA);
        Assert.assertEquals(2.0 + 1.0,
                Vector.dotProduct(this.vector2, this.vector3), DELTA);
    }

    /**
     * Prüft die Methode getLength der Klasse Vector auf Fehler.
     */

    public void testGetLength() {
        Assert.assertEquals(0.0, this.vector1.getLength(), DELTA);
        Assert.assertEquals(Math.sqrt(2.0), this.vector2.getLength(), DELTA);
        Assert.assertEquals(Math.sqrt(4.0 + 1.0 + 9.0),
                this.vector3.getLength(), DELTA);
    }

    /**
     * Prüft die Methode normalize der Klasse Vector auf Fehler.
     */

    public void testNormalize() {
        this.vector1.normalize();
        Assert.assertEquals(0.0, this.vector1.getLength(), DELTA);
        this.vector2.normalize();
        Assert.assertEquals(1.0, this.vector2.getLength(), DELTA);
        this.vector3.normalize();
        Assert.assertEquals(1.0, this.vector3.getLength(), DELTA);
    }

    /**
     * Prüft die Methode getNormalized der Klasse Vector auf Fehler.
     */

    public void testGetNormalized() {
        this.vector1 = this.vector1.getNormalized();
        Assert.assertEquals(0.0, this.vector1.getLength(), DELTA);
        this.vector2 = this.vector2.getNormalized();
        Assert.assertEquals(1.0, this.vector2.getLength(), DELTA);
        this.vector3 = this.vector3.getNormalized();
        Assert.assertEquals(1.0, this.vector3.getLength(), DELTA);
    }
}
Um die Klasse Vector verifizieren zu können, muss ebenfalls nur noch TestVector ausgeführt werden.

java TestVector

.........
Time: 0,02

OK (9 tests)
Jetzt können also die Klassen Perceptron und Vector separat getestet werden. Diese Tests können aber auch zu einer Suite zusammengefasst werden.

TwoTests.java

import junit.framework.Test;
import junit.framework.TestSuite;

/**
 * Diese Klasse fasst die Testfälle TestVector und TestPerceptron
 * zusammen und bietet die Möglichkeit, diese zu testen.
 */

public class TwoTests {

    /**
     * Diese Methode fasst die Testfälle TestVector und TestPerceptron
     * zusammen und gibt diese als Kompositum (Suite) zurück.
     * @return Die Suite
     */

    public static Test suite() {
        TestSuite suite = new TestSuite("Test Vector und Perceptron");
        suite.addTestSuite(TestVector.class);
        suite.addTestSuite(TestPerceptron.class);
        return suite;
    }

    /**
     * Hauptprogramm führt die Testfälle TestVector und TestPerceptron
     * auf Konsolenebene aus.
     */

    public static void main(String[] args) {
        junit.textui.TestRunner.run(TwoTests.suite());
    }
}
Die Zusammenfassung (Suite) der beiden Unit-Tests kann nun ausgeführt werden.

java TwoTests

..........[Grenzfälle fehlen]
Time: 0,01

OK (10 tests)
Mit solchen Suites kann man die Tests ganzer Softwareprojekte zusammenfassen — ein einziger Klick macht es möglich, sie auf einmal komplett zu testen. Wenn dabei kein failed auftaucht, ist (vielleicht) alles korrekt und fehlerfrei. Trotzdem kommt es immer noch auf die Qualität der Testfälle an. Wenn manche Tests gewisse Grenzfälle nicht betrachten oder nicht ausführlich genug sind, kann die Software trotz Unit-Tests fehlerhaft sein!
Streng genommen kann man mit nichts zur Fehlerfreiheit gelangen. Mit dem systematischen Testen, zum Beispiel mit JUnit, kann man nur versuchen, die Wahrscheinlichkeit eines Fehlers zu minimieren. {Unit-Tests tragen zur Gewissensberuhigung der Entwickler bei.}



Info

stefan−baur.de / Verifikation−Beispiel
  • besucht am Freitag, den 12. März 2010 um 15:50 Uhr
  • geändert am Sonntag, den 15. März 2009 von Stefan K. Baur
  • ähnliche Seiten:






Startseite

Copyright © 2004-2009 Stefan K. Baur − Druck20042005200620072008200920102011