Blog

Bedingtes Ignorieren von JUnit-Tests

Barend Garvelink

Aktualisiert Oktober 22, 2025
3 Minuten

Eine nützliche Technik, die ich von Zeit zu Zeit neu erfinde, ist das bedingte Ignorieren von JUnit-Tests. Unit-Tests sollten eigentlich isoliert sein, aber gelegentlich stoßen Sie auf etwas, das Annahmen über die Umgebung macht, wie z.B. Code, der einen plattformspezifischen Shell-Befehl ausführt oder (häufiger) ein Integrationstest, der das Vorhandensein einer Datenbank voraussetzt. Um zu verhindern, dass ein solcher Test ahnungslose Builds beschädigt, können Sie ihn tt>@Ignore, aber das bedeutet, dass Sie den Code bearbeiten müssen, um den Test in einer unterstützten Umgebung auszuführen.

Richtige Maven-Projekte legen ihre Integrationstests in einem separaten Quellordner namens src/it/java ab und fügen eine zusätzliche Ausführung des maven-surefire-plugin in ihre pom.xml ein, die an die Integrationstests Phase des Maven Build-Lebenszyklus gebunden ist. Dies ist die von Maven empfohlene Art, diese einzurichten. Sie passt hervorragend zu den Phasen vor und nach dem Integrationstest, die zum Auf- und Abbau der Umgebungsabhängigkeiten der Integrationstestsuite verwendet werden können, wie z.B. die Initialisierung einer Datenbank in einem bekannten Zustand. An diesem Ansatz ist nichts auszusetzen, aber er ist für die einfachsten Fälle etwas schwerfällig.

In diesen einfachen Situationen ist es einfacher, die Integrationstests im Verzeichnis src/test/java abzulegen und sie zusammen mit allen anderen Tests auszuführen. Sie brauchen jedoch immer noch eine Möglichkeit, sie nur dann auszulösen, wenn die richtige Umgebung vorhanden ist. Dies lässt sich leicht bewerkstelligen, indem Sie Ihren eigenen JUnit TestRunner und einige benutzerdefinierte Annotationen schreiben, wie unten gezeigt.

Der Einstiegspunkt

Der Standard-Testrunner in JUnit 4 ist BlockJUnit4ClassRunner (javadoc, Quellcode). In dieser Klasse müssen wir nur eine einzige Methode überschreiben:

[sourcecode language="java"] protected void runChild(FrameworkMethod method, RunNotifier notifier) [/sourcecode]

Diese Methode wird für jeden Test einmal ausgeführt und überprüft, ob die @Ignore-Anmerkung vorhanden ist. Fügen wir eine eigene Annotation hinzu, mit der wir eine Klasse nur dann ausführen, wenn eine bestimmte Java-Systemeigenschaft gesetzt ist.

Die Anmerkung zur Methode

Wir definieren eine einfache Anmerkung, die auf die Methodenebene abzielt und die Systemeigenschaft definiert, die für die Ausführung der Testmethode gesetzt sein muss:

[sourcecode language="java"] @Target( ElementType.METHOD ) @Retention(RetentionPolicy.RUNTIME) public @interface SystemPropertyCondition { /* Der Name einer Systemeigenschaft, die gesetzt sein muss, damit der Test läuft. / String value(); } [/sourcecode]

Der Testläufer

Das Schreiben des Testläufers ist ähnlich einfach:

[sourcecode language="java"] public class ConditionalTestRunner extends BlockJUnit4ClassRunner { public ConditionalTestRunner(Class klass) { super(klass); } @Override public void runChild(FrameworkMethod method, RunNotifier notifier) { SystemPropertyCondition condition = method.getAnnotation(SystemPropertyCondition.class) if (condition != null && System.getProperty(condition.value()) != null) { super.runChild(method, notifier); } else { notifier.fireTestIgnored(describeChild(method)); } } } [/sourcecode]

Das Verwendungsbeispiel

Um diesen Test-Runner zu verwenden, versehen Sie Ihre Testklasse mit der Annotation @RunWith(Class). Jede der Testmethoden kann dann als bedingt gekennzeichnet werden.

[sourcecode language="java"] @RunWith(ConditionalTestRunner.class) public class SomeExampleTest { @Test @SystemPropertyCondition("com.mycompany.includeConditionalTests") public void testMethodThatRunsConditionally() { // Normaler Testcode geht hier } } [/sourcecode]

Dieser Ansatz lässt sich für mehr Flexibilität leicht erweitern. Wenn Sie beispielsweise in der Lage sein möchten, sowohl ganze Klassen als auch einzelne Methoden mit Anmerkungen zu versehen, machen Sie die Anmerkung zum Ziel sowohl von ElementType.TYPE als auch von ElementType.METHOD und werten Sie in Ihrem Testrunner nicht nur method.getAnnotations(), sondern auch getTestClass().getAnnotations() aus. Es ist nicht schwer, zusätzliche Annotationstypen hinzuzufügen, die Dinge wie das Host-Betriebssystem, Umgebungsvariablen oder einen offenen TCP-Port auf localhost überprüfen.

Sie sollten jedoch bedenken, dass jede einzelne dieser Bedingungen, die Sie Ihrem Code hinzufügen, gegen die ideale Situation verstößt, in der Unit-Tests in jeder Umgebung und in jeder Reihenfolge ausgeführt werden können. Wenden Sie sie mit Bedacht an.

Verfasst von

Barend Garvelink

Contact

Let’s discuss how we can support your journey.