JUnit

+ andere TechDocs
+ Fit
+ HttpUnit
+ JUnit.org
+ JUnit.sourceforge.net
+


JUnit ist ein Java-Werkzeug, mit dem Java-Klassen automatisiert getestet werden können (ursprünglich von Kent Beck und Erich Gamma konzipiert).

Während bei Black-Box-Systemtests und Akzeptanztests die Software als Ganzes und ohne Kenntnis der Internas getestet wird (z.B. mit Fit), wird JUnit im Java-Umfeld eingesetzt für Unit-, Komponenten- und White-Box-Tests, bei denen die Internas der zu testenden Komponente bekannt sind.

Zu den zu testenden Klassen werden Testklassen mit mehreren Testmethoden erzeugt. Mehrere Testklassen können zu Test-Suiten zusammengefasst werden. Das TestRunner-Tool führt die Tests aus und berichtet kummulativ die Ergebnisse.

Besonders moderne "agile" Vorgehensmodelle zum Softwareentwicklungsprozess (z.B. XP, Extreme Programming) werben mit "Test Driven Development" ("TDD") und beführworten extensives Testen und das Erstellen der Tests bevor mit der eigentlichen Kodierung begonnen wird.



Inhalt

  1. Einfaches JUnit-Beispiel
    Einfache Testklasse und Testausführung im Kommandozeilenfenster, Zusammenfassung mehrerer Testklassen zu einer TestSuite, Aufruf des Tests über eine main()-Methode
  2. Testwiederholungen
    Testwiederholungen mit RepeatedTest, Testwiederholung mit Testparametern aus Properties-Dateien
  3. JUnit mit Eclipse
  4. JUnit (und TestNG) mit Maven
  5. Links auf weiterführende Informationen


Einfaches JUnit-Beispiel

Einfache Testklasse und Testausführung im Kommandozeilenfenster

  1. Installieren Sie ein aktuelles Java SE JDK.
  2. Legen Sie ein Projektverzeichnis an (z.B. D:\MeinWorkspace\JUnitTest1), darunter die Verzeichnisse bin, lib, src und test, und unter den letzten beiden jeweils meinpackage:

    [\MeinWorkspace\JUnitTest1]
     |- [bin]
     |- [lib]
     |- [src]
     |   '- [meinpackage]
     '- [test]
         '- [meinpackage]
    

    Die Testklassen werden in einem getrennten Verzeichnisbaum (unter 'test') abgelegt, damit sie später leicht weggelassen werden können. Aber die Package-Struktur des 'src'-Verzeichnisses sollte identisch auch im 'test'-Testverzeichnis wiederholt werden, damit die Testklassen auch Zugriff auf protected-Elemente der zu testenden Klassen haben.

  3. Downloaden Sie von http://www.junit.org eine aktuelle JUnit-Lib (z.B. junit-4.8.2.jar) und speichern Sie diese ins lib-Verzeichnis.
  4. Als zu testende Java-Klasse soll das folgende einfache Beispiel dienen, welches von Zahlen wahlweise das Quadrat oder die Wurzel ermittelt.
    Speichern Sie im src\meinpackage-Verzeichnis die folgende Nutzklassendatei: MeineKlasse.java

    package meinpackage;
    
    public class MeineKlasse
    {
      private String job;
    
      public String getJob() {
        return job;
      }
    
      public void setJob( String job ) {
        this.job = job;
      }
    
      public double myMethod( double x ) throws Exception
      {
        if( "Quadrat".equalsIgnoreCase( job ) )
          return x * x;
        if( "Wurzel".equalsIgnoreCase( job ) )
          return Math.sqrt( x );
        throw new Exception( "Fehler: Aufgabe nicht korrekt definiert." );
      }
    }
    
  5. Speichern Sie im test\meinpackage-Verzeichnis die folgende Testklassendatei: MeineKlasseTest.java

    package meinpackage;
    
    import junit.framework.TestCase;
    
    public class MeineKlasseTest extends TestCase
    {
      MeineKlasse meineKlasse1;
    
      @Override public void setUp() throws Exception
      {
        meineKlasse1 = new MeineKlasse();
        assertEquals( "Anfangs darf kein Job gesetzt sein.",
                      null, meineKlasse1.getJob() );
      }
    
      @Override public void tearDown() throws Exception
      {
        meineKlasse1 = null;
      }
    
      public void testGetAndSetJob()
      {
        meineKlasse1.setJob( "Quadrat" );
        assertEquals( "Job muss 'Quadrat' sein.",
                      "Quadrat", meineKlasse1.getJob() );
      }
    
      public void testDoJobs() throws Exception
      {
        meineKlasse1.setJob( "Quadrat" );
        assertTrue( "Quadrat von '4' muss '16' sein.",
                    16. == meineKlasse1.myMethod( 4 ) );
    
        meineKlasse1.setJob( "Wurzel" );
        assertTrue( "Wurzel von '4' muss '2' sein.",
                    2. == meineKlasse1.myMethod( 4 ) );
    
        meineKlasse1.setJob( null );
        try {
          meineKlasse1.myMethod( 4 );
          fail( "Exception muss geworfen werden, da kein korrekter Job gesetzt." );
        } catch( Exception ex ) {/*ok*/}
      }
    }
    

    In 'setUp()' können Initialisierungen durchgeführt werden.
    In 'tearDown()' kann aufgeräumt werden (z.B. Datenbankverbindungen schließen).

    Die Testmethoden 'test...()' müssen folgende Bedingungen erfüllen, um (per Reflection) als Testmethoden erkannt zu werden:
    - Der Name muss mit 'test' beginnen
    - Sie dürfen keine Parameter haben
    - Sie müssen 'public' und dürfen nicht 'static' sein

    Doku zu den 'assert...()'- und 'fail()'-Methoden finden Sie in der Doku zur Klasse Assert. Beachten Sie die Vorgehensweise, wie mit 'fail()' im 'try'-Block das Werfen von Exceptions kontrolliert wird.

  6. Die Projektstruktur sieht jetzt so aus:

    cd \MeinWorkspace\JUnitTest1

    tree /F

    [\MeinWorkspace\JUnitTest1]
     |- [bin]
     |- [lib]
     |   '- junit-4.8.2.jar
     |- [src]
     |   '- [meinpackage]
     |       '- MeineKlasse.java
     '- [test]
         '- [meinpackage]
             '- MeineKlasseTest.java
    
  7. Öffnen Sie ein Kommandozeilenfenster ('Windows-Taste' + 'R', 'cmd'), compilieren Sie und führen Sie die Tests aus:

    cd \MeinWorkspace\JUnitTest1

    javac -cp bin;lib/* -d bin src/meinpackage/*.java

    javac -cp bin;lib/* -d bin test/meinpackage/*.java

    java -cp bin;lib/* junit.textui.TestRunner meinpackage.MeineKlasseTest

    Sie erhalten:

    OK (2 tests)
    
  8. Bauen Sie in der zu testenden Klasse Fehler ein, um Fehlermeldungen beobachten zu können, und führen Sie die Tests erneut aus.

Zusammenfassung mehrerer Testklassen zu einer TestSuite

  1. Falls Sie viele Testklassen haben, können Sie diese zusammenfassen. Speichern Sie im test\meinpackage-Verzeichnis die folgende Test-Suite-Klasse: AllTests.java

    package meinpackage;
    
    import junit.framework.Test;
    import junit.framework.TestSuite;
    
    public class AllTests extends TestSuite
    {
      public static Test suite()
      {
        TestSuite mySuite = new TestSuite( "Meine Test-Suite" );
        mySuite.addTestSuite( meinpackage.MeineKlasseTest.class );
        // ... weitere Testklassen hinzufügen
        return mySuite;
      }
    }
    

    Sie können auch zum Beispiel pro package alle Testklassen zu einer TestSuite zusammengefassen, und dann diese TestSuites nochmal zu einer TestSuite zusammengefassen.

  2. Führen Sie die Tests aus:

    cd \MeinWorkspace\JUnitTest1

    javac -cp bin;lib/* -d bin src/meinpackage/*.java

    javac -cp bin;lib/* -d bin test/meinpackage/*.java

    java -cp bin;lib/* junit.textui.TestRunner meinpackage.AllTests

    Sie erhalten wieder:

    OK (2 tests)
    

Aufruf des Tests über eine main()-Methode

  1. Diese Option wird normalerweise nicht genutzt, aber der Vollständigkeit halber soll auch vorgestellt werden, wie Sie den TestRunner in einer main()-Methode verwenden könnten. Speichern Sie im test\meinpackage-Verzeichnis die folgende Klasse: TestMain.java

    package meinpackage;
    
    public class TestMain
    {
      public static void main( String[] args )
      {
        junit.textui.TestRunner.run( meinpackage.MeineKlasseTest.class );
      }
    }
    
  2. Führen Sie die Tests aus:

    cd \MeinWorkspace\JUnitTest1

    javac -cp bin;lib/* -d bin src/meinpackage/*.java

    javac -cp bin;lib/* -d bin test/meinpackage/*.java

    java -cp bin;lib/* meinpackage.TestMain

    Sie erhalten wieder:

    OK (2 tests)
    


Testwiederholungen

Testwiederholungen mit RepeatedTest

  1. Erzeugen Sie im test\meinpackage-Verzeichnis die neue Test-Suite-Datei: AllTestsRepeated.java

    package meinpackage;
    
    import junit.framework.Test;
    import junit.framework.TestSuite;
    import junit.extensions.RepeatedTest;
    
    public class AllTestsRepeated extends TestSuite
    {
      public static Test suite()
      {
        TestSuite mySuite = new TestSuite( "Meine Test-Suite" );
        mySuite.addTestSuite( meinpackage.MeineKlasseTest.class );
        // ... weitere Testklassen hinzufügen
        return new RepeatedTest( mySuite, 5 );
      }
    }
    
  2. Führen Sie die Tests aus:

    cd \MeinWorkspace\JUnitTest1

    javac -cp bin;lib/* -d bin src/meinpackage/*.java

    javac -cp bin;lib/* -d bin test/meinpackage/*.java

    java -cp bin;lib/* junit.textui.TestRunner meinpackage.AllTestsRepeated

    Die Tests werden jetzt fünfmal wiederholt. Das macht bei diesem einfachen Test natürlich keinen Sinn, aber es gibt viele Situationen, bei denen Fehler erst beim wiederholten Versuch auftreten, zum Beispiel bei konkurrierenden Threads, Message Queues oder bei Einbindung externer Komponenten über Netzwerk- oder Datenbankverbindungen.

Testwiederholung mit Testparametern aus Properties-Dateien

  1. Das folgende Beispiel sucht mit 1 beginnend fortlaufend durchnummerierte Properties-Dateien mit den Namen 'Test1.properties', 'Test2.properties' usw. und zählt sie. Entsprechend der Anzahl der gefundenen Properties-Dateien wird genau so oft der Test wiederholt mit für jeden Test neue geladenen Testparametern aus der jeweils entsprechenden Properties-Datei.
    Speichern Sie im test\meinpackage-Verzeichnis die folgende Testklassendatei: MeineKlassePropTest.java

    package meinpackage;
    
    import java.io.FileInputStream;
    import java.util.Properties;
    import junit.extensions.RepeatedTest;
    import junit.framework.*;
    
    public class MeineKlassePropTest extends TestCase
    {
      static int counterForUsedPropFile = 0;  // counter for properties files
    
      public static Test suite()
      {
        counterForUsedPropFile = 0;
        // Count properties files:
        int i = 0;
        Properties prop = new Properties();
        while( true ) {
          try {
            prop.load( new FileInputStream( "./test/Test" + ++i + ".properties" ) );
          } catch( Exception ex ) {
            break;
          }
        }
        // Create RepeatedTest, for each properties file one test:
        TestSuite mySuite = new TestSuite( "TestRepeater" );
        mySuite.addTestSuite( MeineKlassePropTest.class );
        // If no properties file found, we set '1' for getting an error
        // message with 'fail()' in 'testReadParmsFromPropFile()':
        return new RepeatedTest( mySuite, ( 0 < --i ) ? i : 1 );
      }
    
      public void testReadParmsFromPropFile() throws Exception
      {
        // Read parameters from properties file:
        String propFileName = "./test/Test" + ++counterForUsedPropFile + ".properties";
        Properties prop = new Properties();
        try {
          prop.load( new FileInputStream( propFileName ) );
        } catch( Exception ex ) {
          fail( "Fehler: Properties-Datei '" + propFileName + "' fehlt. " );
        }
        String job  = prop.getProperty( "job" );
        double val  = Double.parseDouble( prop.getProperty( "val"  ) );
        double rslt = Double.parseDouble( prop.getProperty( "rslt" ) );
        // Test 'MeineKlasse':
        MeineKlasse meineKlasse1 = new MeineKlasse();
        meineKlasse1.setJob( job );
        if( "Quadrat".equalsIgnoreCase( job ) ||
             "Wurzel".equalsIgnoreCase( job ) ) {
          assertEquals( job + " von '" + val + "': ",
                        rslt, meineKlasse1.myMethod( val ), 0.001 );
        } else {
          fail( "'job' muss 'Quadrat' oder 'Wurzel' sein, ist aber '" + job + "'." );
        }
      }
    }
    
  2. Sie benötigen zusätzlich Properties-Dateien. Speichern Sie im Unterverzeichnis 'test' die beiden folgenden Properties-Dateien:

    Test1.properties

    job=Wurzel
    val=64
    rslt=8
    

    Test2.properties

    job=Quadrat
    val=64
    rslt=4096
    

    Ergänzen Sie weitere 'TestXX.properties'-Dateien.

  3. Führen Sie die Tests aus:

    cd \MeinWorkspace\JUnitTest1

    javac -cp bin;lib/* -d bin src/meinpackage/*.java

    javac -cp bin;lib/* -d bin test/meinpackage/*.java

    java -cp bin;lib/* junit.textui.TestRunner meinpackage.MeineKlassePropTest



JUnit mit Eclipse

Wesentlich komfortabler ist der Einsatz von JUnit, wenn Sie die gute Integration von JUnit in Eclipse nutzen. Dazu soll das letzte Projekt noch mal von Grund auf neu erstellt werden.

  1. Legen Sie in Eclipse ein neues Java-Projekt an, entweder über 'File' | 'New' | 'Project...' | 'Java Project' oder mit rechter Maustaste im 'Package Explorer' | 'New' | 'Project...' | 'Java Project'.
    Geben Sie als 'Project name' 'JUnitTest2' ein und wählen Sie 'Create separate folders for sources and class files' und 'Finish'.
  2. Legen Sie ein Package an, indem Sie im 'Package Explorer' mit der rechten Maustaste auf den neu erscheinenden Projektnamen klicken und 'New' | 'Package' wählen.
    Geben Sie als 'Name' 'meinpackage' ein.
  3. Generieren Sie eine zu testende Klasse, indem Sie im 'Package Explorer' mit der rechten Maustaste auf den neu erscheinenden Package-Namen klicken und 'New' | 'Class' wählen.
    Achten Sie darauf, dass als 'Source Folder' 'JUnitTest2/src' und als 'Package' 'meinpackage' eingestellt ist, dass der Radiobutton auf 'public' steht und alle Checkboxen ausgeschalten sind.
    Tragen Sie als 'Name' 'MeineKlasse' ein.
  4. Ersetzen Sie den Inhalt der neuen im Editorfenster erscheinenden Datei 'MeineKlasse.java' durch den oben unter 'MeineKlasse.java' genannten Inhalt.
    Speichern Sie mit 'Strg+S' und stellen Sie sicher, dass im 'Problems'-View keine Fehler gemeldet werden ('Window' | 'Show View' | 'Problems').
  5. Die Testfälle sollen in einem separaten Sourcebaum angelegt werden. Klicken Sie dafür im 'Package Explorer' mit der rechten Maustaste auf den Projektnamen 'JUnitTest2' und wählen Sie 'Properties' | 'Java Build Path' | Tabulatorreiter 'Source' | 'Add Folder...' | 'Create New Folder...' und geben Sie als 'Folder name:' 'test' ein.
    Im 'Package Explorer' sehen Sie jetzt die beiden Sourcepfade 'src' und 'test'.
  6. Klicken Sie im 'Package Explorer' mit der rechten Maustaste auf den Dateinamen 'MeineKlasse.java' und wählen Sie 'New' | 'JUnit Test Case'. Beantworten Sie die Frage, ob 'junit.jar' dem 'build path' hinzugefügt werden soll, mit 'Yes'.
    Betätigen Sie den Button 'Browse...' neben dem 'Source Folder'-Editierfeld und wählen Sie 'test' statt 'src'. Der angezeigte 'Source Folder' lautet jetzt 'JUnitTest2/test'.
    Achten Sie darauf, dass als 'Package' 'meinpackage' und als 'Name' 'MeineKlasseTest' eingestellt ist.
  7. Ersetzen Sie den Inhalt der neuen im Editorfenster erscheinenden Datei 'MeineKlasseTest.java' durch den oben unter 'MeineKlasseTest.java' genannten Inhalt.
    Speichern Sie mit 'Strg+S' und stellen Sie sicher, dass im 'Problems'-View keine Fehler gemeldet werden ('Window' | 'Show View' | 'Problems').
  8. Setzen Sie den Cursor in das Editorfenster zu 'MeineKlasseTest.java' und wählen Sie 'Run' | 'Run As' | 'JUnit Test'. Der 'JUnit'-View öffnet sich und nach Ablauf der Tests erscheint der grüne 'JUnit'-Balken. Klicken Sie unter dem grünen Balken auf den 'Hierarchy'-Tabulatorreiter und auf das '[+]' vor 'meinpackage.MeineKlasseTest'. Jetzt können Sie die Testmethoden auch einzeln anklicken und laufen lassen.
  9. Klicken Sie im 'Package Explorer' mit der rechten Maustaste auf den Dateinamen 'MeineKlasseTest.java' und wählen Sie 'New' | 'Other...' | '[+] Java' | '[+] JUnit' | 'JUnit Test Suite'. Achten Sie darauf, dass als 'Source Folder' 'JUnitTest2/test' und als 'Package' 'meinpackage' eingestellt ist und dass unter 'Test Classes to include in Suite:' 'MeineKlasseTest' ausgewählt ist.
  10. Die neu entstandene Klasse 'AllTests.java' können Sie so lassen. Setzen Sie den Cursor in das Editierfenster zu dieser Klasse und wählen Sie 'Run' | 'Run As' | 'JUnit Test'. Im 'JUnit'-View erscheint nach Ablauf der Tests wieder der grüne 'JUnit'-Balken. Aber unter 'Hierarchy' sehen Sie diesmal eine Hierarchieebene mehr. (Eventuell müssen Sie den 'JUnit'-View nach vorne holen, entweder durch Klick auf den 'JUnit'-Tabulatorreiter oder über 'Window' | 'Show View' | 'Other...' | '[+] Java' | 'JUnit'.)
  11. Außer über 'Run' | 'Run As' | 'JUnit Test' können Sie die JUnit-Tests auch starten, indem Sie im 'Package Explorer' mit der rechten Maustaste auf den Dateinamen oder auch auf Package- oder Modulnamen klicken und 'Run As' | 'JUnit Test' wählen. Auf diese Art können Sie alle Tests des Packages oder Moduls in Einem durchlaufen.
  12. Sehen Sie sich wieder mit tree /F das JUnitTest2-Projektverzeichnis an.


JUnit (und TestNG) mit Maven

In maven.htm finden Sie sehr viele JUnit (und TestNG) verwendende Beispiele.



Links auf weiterführende Informationen





Weitere Themen: andere TechDocs | Fit | HttpUnit | Vorgehensmodelle zum Softwareentwicklungsprozess
© 1998-2007 Torsten Horn, Aachen