Gabi und Sascha
Tags - Kategorien : Alle | Berlin | Bücher | Fotografie | Java | Linkhalde | Weichware | Verfassung

Die JUnit ist schon vor einiger Zeit in der Version 4 erschienen. Die erste Auffälligkeit ist die geänderte Packagestruktur. War das Basispackage vor der Version 4 unter junit definiert, so ist es jetzt unter org.junit zu finden. Dies allein ist natürlich kein Grund für einen derartigen Versionssprung. Dieser wir vielmehr durch neue Konzepte für die Testentwicklung gerechtfertigt. Die JUnit 4 übernimmt das Konzept der Metaauszeichnungen für Test aus der NUnit und verwendet Annotationen aus Java 5, um Tests zu beschreiben. Dadurch wird das API erheblich schlanker.

Einfacher JUnit 4 Test

Eine erste kleine Testklasse:


    package de.speexx.playground.sascha.junit4;

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

    public class JUnit4Test {

        @Test 
        public void simpleAssert() throws Exception { 
            Assert.assertEquals(1, 1);
        }
    }

Zuerst fällt auf, dass die Testklasse nicht mehr von TestCase abgeleitet ist. Die Klasse existiert in der offiziellen JUnit 4 API, die durch Javadoc beschrieben ist, nicht mehr. Intern wird sie für die Abwärtskompatibilität allerdings mitgeliefert.

Damit unter der JUnit 4 eine Testmethode erkannt wird, muss sie mit der Annotation @Test markiert werden. Eine derart annotierte Methode muss nicht mehr mit dem Prefix test beginnen, um vom JUnit Runner als Testmethode erkannt zu werden.

Nach dem compilieren kann der Test ausgeführt werden:


    sascha@linux:> java -cp ./:./junit-4.0.jar org.junit.runner.JUnitCore de.speexx.playground.sascha.junit4.JUnit4Test
    JUnit version 4.0
    .

    Time: 0

    OK (1 test)

Set up und tear down

Durch das Fehlen der Ableitung von TestCase entfällt natürlich auch die Möglichkeit durch den Aufruf von setUp vor der Ausführung jeder Testmethode den Test zu initialisieren. Dies wird durch die Annotation @Before vor einer beliebigen Methode ersetzt.


    package de.speexx.playground.sascha.junit4;

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

    public class JUnit4Test {

        private int simpleValue = 0;
    
        @Test 
        public void simpleAssert() throws Exception { 
            Assert.assertEquals(this.simpleValue, 2);
        }

        @Before 
        public void init() {
            this.simpleValue = 2;
        }
    }

In der vorliegenden Version 4.0 kann auch mehr als eine Methode mit der Annotation @Before versehen werden. Dies steht meiner Meinung nach im Widerspruch zur Dokumentation, in der es heisst: Annotating a public void method with @Before causes that method to be run before the @Test method. Auch ist die Abfolge der Aufrufe nicht definiert, so dass auf diesen Mechanismus vorerst verzichtet werden sollte. Allerdings werden @Before annotierte Methoden einer eventuell vorhandenen Superklasse vor der in der aktuellen Klasse aufgerufen.

Die Methode tearDown() aus TestCase wird durch die Annotation @After ersetzt. Auch hier gilt, dass die Annotation mehrfach vorkommen kann.

Klassenweites set up und tear down

Neben dem set up und tear down vor jedem Testmethodenaufruf ist es mit der JUnit 4 auch sehr einfach möglich dies einmalig, one-time set up, für die Testklasse auszuführen. Hierfür muss eine public static void Methode mit der Annotation @BeforeClass versehen werden. Für das one-time tear down mit der Annotation @AfterClass.


    package de.speexx.playground.sascha.junit4;

    import org.junit.Test;
    import org.junit.BeforeClass;
    import static org.junit.Assert.assertEquals;

    public class JUnit4Test {

        private static int SIMPLE_VALUE = 0;
    
        @Test 
        public void simpleAssert() throws Exception { 
            assertEquals(SIMPLE_VALUE, 2);
        }

        @Test 
        public void anotherSimpleAssert() throws Exception { 
            assertEquals(SIMPLE_VALUE, 2);
        }

        @BeforeClass 
        public static void init() {
            SIMPLE_VALUE = 2;
        }
    }

Zusätzlich wird im Beispiel die assertEquals Methode statisch importiert.

Tests ignorieren

Manchmal ist es im Entwicklungsprozess nötig, dass Testmethoden nicht ausgeführt werden sollen. Dies wird durch die Annotation @Ignore erreicht, die optional mit einem beschreibenden Wert versehen werden kann.


    package de.speexx.playground.sascha.junit4;

    import org.junit.Test;
    import org.junit.Ignore;
    import static org.junit.Assert.assertEquals;

    public class JUnit4Test {

        @Test 
        public void simpleAssert() throws Exception { 
            assertEquals(1, 1);
        }

        @Ignore("not yet ready")
        @Test 
        public void anotherSimpleAssert() throws Exception { 
            assertEquals(1, 2);
        }
    }

Bei der Ausführung wird für einen ignorierten Test ein I anstatt eines Punktes für einen erfolgreichen Test ausgegeben.


    sascha@linux:> java -cp ./:./junit-4.0.jar org.junit.runner.JUnitCore de.speexx.playground.sascha.junit4.JUnit4Test
    JUnit version 4.0
    .I

    Time: 0

    OK (1 test)

Abwärtskompatibilität

Trotz dieser Änderungen ist die JUnit weiterhin kompatibel zu den 3.x Versionen, so dass bestehende Tests nicht angepasst werden müssen. Allerdings haben einige Spielereien gezeigt, dass ein mixen beider Vorgehensweisen nicht geeignet ist. Deswegen sollten Tests, die auf der JUnit 4 basieren in neuen Testklassen aufgenommen werden.

Einsatz

Es stellt sich natürlich die Frage, ob und wann man beginnen soll die JUnit 4 in einem produktiven Umfeld einzusetzen. Dies ist von Projekt zu Projekt unterschiedlich. Da die neue Version zwingend Java 5 voraussetzt, macht dies natürlich nur für solche Entwicklungen Sinn, die bereits damit arbeiten. Allerdings kommt es dann natürlich auch immer auf die Entwicklungsumgebung an. So müssen beispielsweise die Eclipse Test Plug-Ins an das neue API angepasst werden und auch das Projektmanagement-Tool Maven unterstützt das neue Test API, sowohl in der Version 1.x und 2, noch nicht. Für den professionellen Einsatz müssen diese erst nachziehen. Gerade bei einem solch zentralen Tool wie Maven ist dies nicht unbedingt trivial. Es bewirkt, dass der gesamte Entwicklungsprozess auf Java 5 umgestellt werden muss.

Fazit

Mit dem Major Upgrade hat die JUnit einen deutlichen Sprung nach vorne gemacht. Sie nutzt die mit Java 5 eingeführte Möglichkeit der Annotationen konsequent aus und verschlank dadurch das API dramatisch. Dabei wird einmal mehr deutlich welch mächtiges Sprachfeature Metainformationen sind und wie sie das Design von Frameworks grundsätzlich verändern. Bei der JUnit 4 kann man kaum noch von einem Test-Framework sprechen (Don't call us, we call you), sondern von definierten Metainformationen und einer beliebigen Ausführungseinheit. Diese starke Entkopplung ist ein grosser Gewinn, der das Redesign auf jeden Fall gerechtfertigt hat.