/**
* 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;
}
}
}
Test
voranstellt.
Die Testklasse für die Klasse
Perceptron
trägt also den Namen
TestPerceptron.
Perceptron
enthält nur eine einzige Methode namens
activate,
welche getestet werden kann.
Die dazugehörige Testmethode bezeichnet man hier
testActivate.
Dem nach Konvention kleingeschriebenen
test
folgt der Name der zu testenden Methode.
Jede Methode, die mit dem kleingeschriebenen Test anfängt, wird von JUnit automatisch als Testmethode erkannt,
deshalb müssen Testmethodennamen stets mit
test
beginnen
(Alternative ab JUnit4 mit @Test vor Methodendeklaration).
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.
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.
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]");
}
}
Perceptron
verifizieren zu können,
muss nur noch
TestPerceptron
ausgeführt werden.
.[Grenzfälle fehlen]
Time: 0,02
OK (1 test)
Vector
gezeigt.
/**
* 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;
}
}
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);
}
}
Vector
verifizieren zu können,
muss ebenfalls nur noch
TestVector
ausgeführt werden.
.........
Time: 0,02
OK (9 tests)
Perceptron
und
Vector
separat getestet werden.
Diese Tests können aber auch zu einer
Suite
zusammengefasst werden.
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());
}
}
..........[Grenzfälle fehlen]
Time: 0,01
OK (10 tests)
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!