JUnit 4.8 enthält eine nette neue Funktion namens "Kategorien", mit der Sie bestimmte Arten von Tests zusammenfassen können. Dies ist sehr nützlich, z. B. um separate Testläufe für langsame und schnelle Tests durchzuführen. Ich kenne die in den Versionshinweisen zu JUnit 4.8 erwähnten Dinge , möchte aber wissen, wie ich tatsächlich alle Tests ausführen kann, die mit einer bestimmten Kategorie versehen sind.
Die Versionshinweise zu JUnit 4.8 zeigen eine Beispielsuite-Definition, in der die SuiteClasses-Annotation die Tests aus einer bestimmten Kategorie auswählt, die ausgeführt werden sollen:
@RunWith(Categories.class)
@IncludeCategory(SlowTests.class)
@SuiteClasses( { A.class, B.class }) // Note that Categories is a kind of Suite
public class SlowTestSuite {
// Will run A.b and B.c, but not A.a
}
Weiß jemand, wie ich alle Tests in der Kategorie SlowTests ausführen kann? Es scheint, dass Sie die SuiteClasses-Annotation haben müssen ...
java
unit-testing
junit
junit4
Kaitsu
quelle
quelle
Antworten:
Ich habe einen möglichen Weg gefunden, um das zu erreichen, was ich will, aber ich halte dies nicht für die bestmögliche Lösung, da sie auf der ClassPathSuite-Bibliothek basiert, die nicht Teil von JUnit ist.
Ich definiere die Testsuite für langsame Tests wie folgt:
@RunWith(Categories.class) @Categories.IncludeCategory(SlowTests.class) @Suite.SuiteClasses( { AllTests.class }) public class SlowTestSuite { }
Die AllTests-Klasse ist wie folgt definiert:
@RunWith(ClasspathSuite.class) public class AllTests { }
Ich musste hier die ClassPathSuite-Klasse aus dem ClassPathSuite- Projekt verwenden. Es werden alle Klassen mit Tests gefunden.
quelle
Hier sind einige der Hauptunterschiede zwischen TestNG und JUnit, wenn es um Gruppen geht (oder Kategorien, wie JUnit sie nennt):
JUnits werden eingegeben (Anmerkungen), während TestNGs Zeichenfolgen sind. Ich habe diese Wahl getroffen, weil ich beim Ausführen von Tests reguläre Ausdrücke verwenden wollte, z. B. "Alle Tests ausführen, die zur Gruppe" Datenbank * "gehören. Außerdem muss ich immer dann eine neue Anmerkung erstellen, wenn Sie eine neue erstellen müssen Kategorie ist ärgerlich, obwohl es den Vorteil hat, dass eine IDE Ihnen sofort mitteilt, wo diese Kategorie verwendet wird (TestNG zeigt Ihnen dies in seinen Berichten).
TestNG trennt Ihr statisches Modell (den Code Ihrer Tests) sehr deutlich vom Laufzeitmodell (welche Tests ausgeführt werden). Wenn Sie zuerst die Gruppen "Front-End" und dann "Servlets" ausführen möchten, können Sie dies tun, ohne etwas neu kompilieren zu müssen. Da JUnit Gruppen in Anmerkungen definiert und Sie diese Kategorien als Parameter für den Runner angeben müssen, müssen Sie Ihren Code normalerweise neu kompilieren, wenn Sie eine andere Gruppe von Kategorien ausführen möchten, was meiner Meinung nach den Zweck zunichte macht.
quelle
Ein Nachteil von Kaitsus Lösung ist, dass Eclipse Ihre Tests zweimal und die SlowTests dreimal ausführt, wenn alle Tests in einem Projekt ausgeführt werden. Dies liegt daran, dass die Eclipse alle Tests ausführt, dann die AllTests-Suite und dann die SlowTestSuite.
Hier ist eine Lösung, bei der Unterklassen der Kaitsu-Lösungstestläufer erstellt werden, um die Suiten zu überspringen, sofern keine bestimmte Systemeigenschaft festgelegt ist. Ein beschämender Hack, aber alles, was ich mir bisher ausgedacht habe.
@RunWith(DevFilterClasspathSuite.class) public class AllTests {}
.
@RunWith(DevFilterCategories.class) @ExcludeCategory(SlowTest.class) @SuiteClasses(AllTests.class) public class FastTestSuite { }
.
public class DevFilterCategories extends Suite { private static final Logger logger = Logger .getLogger(DevFilterCategories.class.getName()); public DevFilterCategories(Class<?> suiteClass, RunnerBuilder builder) throws InitializationError { super(suiteClass, builder); try { filter(new CategoryFilter(getIncludedCategory(suiteClass), getExcludedCategory(suiteClass))); filter(new DevFilter()); } catch (NoTestsRemainException e) { logger.info("skipped all tests"); } assertNoCategorizedDescendentsOfUncategorizeableParents(getDescription()); } private Class<?> getIncludedCategory(Class<?> klass) { IncludeCategory annotation= klass.getAnnotation(IncludeCategory.class); return annotation == null ? null : annotation.value(); } private Class<?> getExcludedCategory(Class<?> klass) { ExcludeCategory annotation= klass.getAnnotation(ExcludeCategory.class); return annotation == null ? null : annotation.value(); } private void assertNoCategorizedDescendentsOfUncategorizeableParents(Description description) throws InitializationError { if (!canHaveCategorizedChildren(description)) assertNoDescendantsHaveCategoryAnnotations(description); for (Description each : description.getChildren()) assertNoCategorizedDescendentsOfUncategorizeableParents(each); } private void assertNoDescendantsHaveCategoryAnnotations(Description description) throws InitializationError { for (Description each : description.getChildren()) { if (each.getAnnotation(Category.class) != null) throw new InitializationError("Category annotations on Parameterized classes are not supported on individual methods."); assertNoDescendantsHaveCategoryAnnotations(each); } } // If children have names like [0], our current magical category code can't determine their // parentage. private static boolean canHaveCategorizedChildren(Description description) { for (Description each : description.getChildren()) if (each.getTestClass() == null) return false; return true; } }
.
public class DevFilterClasspathSuite extends ClasspathSuite { private static final Logger logger = Logger .getLogger(DevFilterClasspathSuite.class.getName()); public DevFilterClasspathSuite(Class<?> suiteClass, RunnerBuilder builder) throws InitializationError { super(suiteClass, builder); try { filter(new DevFilter()); } catch (NoTestsRemainException e) { logger.info("skipped all tests"); } } }
.
public class DevFilter extends Filter { private static final String RUN_DEV_UNIT_TESTS = "run.dev.unit.tests"; @Override public boolean shouldRun(Description description) { return Boolean.getBoolean(RUN_DEV_UNIT_TESTS); } @Override public String describe() { return "filter if "+RUN_DEV_UNIT_TESTS+" system property not present"; } }
Fügen Sie in Ihrem FastTestSuite-Launcher einfach -Drun.dev.unit.tests = true zu den VM-Argumenten hinzu. (Beachten Sie, dass diese Lösung auf eine schnelle Testsuite anstatt auf eine langsame verweist.)
quelle
Um kategorisierte Tests auszuführen, ohne sie alle in
@Suite.SuiteClasses
Anmerkungen explizit anzugeben , können Sie Ihre eigene Implementierung von Suite bereitstellen. Zum Beispielorg.junit.runners.ParentRunner
kann a erweitert werden. Anstatt ein Array von Klassen zu verwenden, die von bereitgestellt werden@Suite.SuiteClasses
, sollte die neue Implementierung nach kategorisierten Tests im Klassenpfad suchen.Sehen Sie sich dieses Projekt als Beispiel für einen solchen Ansatz an. Verwendung:
@Categories(categoryClasses = {IntegrationTest.class, SlowTest.class}) @BasePackage(name = "some.package") @RunWith(CategorizedSuite.class) public class CategorizedSuiteWithSpecifiedPackage { }
quelle
Ich bin mir nicht sicher, was genau Ihr Problem ist.
Fügen Sie einfach alle Tests zu einer Suite (oder einer Reihe von Suiten) hinzu. Verwenden Sie dann die Annotation "Categories Runner" und "Include / ExcludeCategory", um die Kategorien anzugeben, die Sie ausführen möchten.
Eine gute Idee könnte sein, eine Suite mit allen Tests und ein paar separate Suiten zu haben, die sich auf die erste beziehen und die verschiedenen Kategorien angeben, die Sie benötigen.
quelle
Keine direkte Antwort auf Ihr Problem, aber vielleicht könnte der allgemeine Ansatz verbessert werden ...
Warum sind Ihre Tests langsam? Vielleicht dauert die Einrichtung lange (Datenbank, E / A usw.), vielleicht testen die Tests zu viel? Wenn dies der Fall ist, würde ich die realen Unit-Tests von den "lang laufenden" trennen, bei denen es sich häufig tatsächlich um Integrationstests handelt.
In meinen Setups habe ich Staging env, wo Unit-Tests häufig ausgeführt werden und Integrationstests ständig, aber seltener (z. B. nach jedem Commit in der Versionskontrolle). Ich habe noch nie mit Gruppierung für Komponententests gearbeitet, weil sie insgesamt lose miteinander verbunden sein sollten. Ich arbeite nur mit der Gruppierung und Beziehung von Testfällen in Integrationstest-Setups (aber mit TestNG).
Gut zu wissen, dass JUnit 4.8 einige Gruppierungsfunktionen eingeführt hat.
quelle