JUnit erstellt für jede @ Test-Methode immer eine Instanz der Testklasse. Dies ist eine grundlegende Entwurfsentscheidung , um das Schreiben von Tests ohne Nebenwirkungen zu vereinfachen. Gute Tests haben keine Abhängigkeiten in der Reihenfolge der Ausführung (siehe ERSTE ), und das Erstellen neuer Instanzen der Testklasse und ihrer Instanzvariablen für jeden Test ist entscheidend, um dies zu erreichen. Einige Test-Frameworks verwenden für alle Tests dieselbe Testklasseninstanz wieder, was zu mehr Möglichkeiten führt, versehentlich Nebenwirkungen zwischen Tests zu erzeugen.
Und da jede Testmethode eine eigene Instanz hat, ist es nicht sinnvoll, dass die @ BeforeClass / @ AfterClass-Methoden Instanzmethoden sind. Ansonsten, auf welcher der Testklasseninstanzen sollten die Methoden aufgerufen werden? Wenn die Methoden @ BeforeClass / @ AfterClass auf Instanzvariablen verweisen könnten, hätte nur eine der @ Test-Methoden Zugriff auf dieselben Instanzvariablen - der Rest hätte die Instanzvariablen auf ihren Standardwerten - und die @ Die Testmethode wird zufällig ausgewählt, da die Reihenfolge der Methoden in der .class-Datei nicht angegeben / vom Compiler abhängig ist (IIRC, Javas Reflection-API gibt die Methoden in derselben Reihenfolge zurück, in der sie in der .class-Datei deklariert sind, obwohl auch dieses Verhalten ist nicht spezifiziert - ich habe eine Bibliothek geschrieben um sie tatsächlich nach ihren Zeilennummern zu sortieren).
Daher ist es die einzig vernünftige Lösung, diese Methoden als statisch zu erzwingen.
Hier ist ein Beispiel:
public class ExampleTest {
@BeforeClass
public static void beforeClass() {
System.out.println("beforeClass");
}
@AfterClass
public static void afterClass() {
System.out.println("afterClass");
}
@Before
public void before() {
System.out.println(this + "\tbefore");
}
@After
public void after() {
System.out.println(this + "\tafter");
}
@Test
public void test1() {
System.out.println(this + "\ttest1");
}
@Test
public void test2() {
System.out.println(this + "\ttest2");
}
@Test
public void test3() {
System.out.println(this + "\ttest3");
}
}
Welche Drucke:
beforeClass
ExampleTest@3358fd70 before
ExampleTest@3358fd70 test1
ExampleTest@3358fd70 after
ExampleTest@6293068a before
ExampleTest@6293068a test2
ExampleTest@6293068a after
ExampleTest@22928095 before
ExampleTest@22928095 test3
ExampleTest@22928095 after
afterClass
Wie Sie sehen können, wird jeder der Tests mit einer eigenen Instanz ausgeführt. Was JUnit macht, ist im Grunde dasselbe:
ExampleTest.beforeClass();
ExampleTest t1 = new ExampleTest();
t1.before();
t1.test1();
t1.after();
ExampleTest t2 = new ExampleTest();
t2.before();
t2.test2();
t2.after();
ExampleTest t3 = new ExampleTest();
t3.before();
t3.test3();
t3.after();
ExampleTest.afterClass();
Die kurze Antwort lautet: Es gibt keinen guten Grund dafür, dass es statisch ist.
Wenn Sie Junit zum Ausführen von DBUnit-basierten DAO-Integrationstests verwenden, verursacht das statische Erstellen allerlei Probleme. Die statische Anforderung beeinträchtigt die Abhängigkeitsinjektion, den Zugriff auf den Anwendungskontext, die Ressourcenbehandlung, die Protokollierung und alles, was von "getClass" abhängt.
quelle
@PostConstruct
zum Einrichten und@AfterClass
Abreißen. Ich ignoriere die statischen von Junit insgesamt. Für DAO-Tests habe ich dann meine eigeneTestCaseDataLoader
Klasse geschrieben, die ich mit diesen Methoden aufrufe.@PostConstruct
und sich@AfterClass
genauso verhält wie@Before
und@After
. Tatsächlich werden Ihre Methoden für jede Testmethode und nicht einmal für die gesamte Klasse aufgerufen (wie Esko Luontola in seiner Antwort feststellt, wird für jede Testmethode eine Klasseninstanz erstellt). Ich kann den Nutzen Ihrer Lösung nicht sehen (es sei denn, ich vermisse etwas)Die JUnit-Dokumentation scheint knapp zu sein, aber ich denke mal: Vielleicht erstellt JUnit eine neue Instanz Ihrer Testklasse, bevor jeder Testfall ausgeführt wird. Die einzige Möglichkeit für Ihren "Fixture" -Status, über mehrere Läufe hinweg zu bestehen, besteht darin, dass er statisch ist, was möglich ist Stellen Sie sicher, dass Ihr fixtureSetup (@ BeforeClass-Methode) statisch ist.
quelle
Dies wird jedoch die ursprüngliche Frage nicht beantworten. Es wird das offensichtliche Follow-up beantworten. So erstellen Sie eine Regel, die vor und nach einer Klasse sowie vor und nach einem Test funktioniert.
Um dies zu erreichen, können Sie dieses Muster verwenden:
Vor (Klasse) erstellt die JPAConnection die Verbindung einmal, nachdem (Klasse) sie geschlossen hat.
getEntityManger
JPAConnection
Gibt eine innere Klasse zurück , die den EntityManager von jpa implementiert und auf die Verbindung innerhalb von zugreifen kannjpaConnection
. Vor (Test) beginnt eine Transaktion, nach (Test) wird sie erneut zurückgesetzt.Dies ist nicht threadsicher, kann aber so gemacht werden.
Ausgewählter Code von
JPAConnection.class
quelle
Es scheint, dass JUnit für jede Testmethode eine neue Instanz der Testklasse erstellt. Probieren Sie diesen Code aus
Die Ausgabe ist 0 0 0
Dies bedeutet, dass wenn die @ BeforeClass-Methode nicht statisch ist, sie vor jeder Testmethode ausgeführt werden muss und es keine Möglichkeit gibt, zwischen der Semantik von @ Beefore und @ BeeClass zu unterscheiden
quelle
Es gibt zwei Arten von Anmerkungen:
Daher muss @BeforeClass als statisch deklariert werden, da es einmal aufgerufen wird. Sie sollten auch berücksichtigen, dass statisch ist die einzige Möglichkeit, um eine ordnungsgemäße "Status" -Verbreitung zwischen Tests sicherzustellen (das JUnit-Modell schreibt eine Testinstanz pro @Test vor), und da in Java nur statische Methoden auf statische Daten zugreifen können ... @BeforeClass und @ AfterClass kann nur auf statische Methoden angewendet werden.
Dieser Beispieltest sollte die Verwendung von @BeforeClass und @Before klarstellen:
Ausgabe:
quelle
Gemäß JUnit 5 scheint die Philosophie, eine neue Instanz pro Testmethode strikt zu erstellen, etwas gelockert worden zu sein. Sie haben hinzugefügt eine Anmerkung , die nur einmal eine Testklasse instanziiert wird. Diese Annotation ermöglicht daher auch, dass Methoden, die mit @ BeforeAll / @ AfterAll (die Ersetzungen von @ BeforeClass / @ AfterClass) annotiert sind, nicht statisch sind. Also eine Testklasse wie diese:
würde drucken:
Sie können Objekte also tatsächlich einmal pro Testklasse instanziieren. Dies macht es natürlich zu Ihrer eigenen Verantwortung, zu vermeiden, dass Objekte mutiert werden, die auf diese Weise instanziiert werden.
quelle
Um dieses Problem zu beheben, ändern Sie einfach die Methode
zu
und alles, was in dieser Methode definiert ist, um
static
.quelle