JUnit crée toujours une instance de la classe de test pour chaque méthode @Test. Il s'agit d'une décision de conception fondamentale pour faciliter l'écriture de tests sans effets secondaires. Les bons tests n'ont pas de dépendances d'ordre d'exécution (voir FIRST ) et la création de nouvelles instances de la classe de test et de ses variables d'instance pour chaque test est cruciale pour y parvenir. Certains frameworks de test réutilisent la même instance de classe de test pour tous les tests, ce qui augmente les possibilités de créer accidentellement des effets secondaires entre les tests.
Et comme chaque méthode de test a sa propre instance, cela n'a aucun sens que les méthodes @ BeforeClass / @ AfterClass soient des méthodes d'instance. Sinon, sur laquelle des instances de classe de test les méthodes doivent-elles être appelées? S'il était possible pour les méthodes @ BeforeClass / @ AfterClass de référencer des variables d'instance, alors une seule des méthodes @Test aurait accès à ces mêmes variables d'instance - les autres auraient les variables d'instance à leurs valeurs par défaut - et le @ La méthode de test serait sélectionnée au hasard, car l'ordre des méthodes dans le fichier .class n'est pas spécifié / dépend du compilateur (IIRC, l'API de réflexion de Java renvoie les méthodes dans le même ordre qu'elles sont déclarées dans le fichier .class, bien que ce comportement soit également n'est pas spécifié - j'ai écrit une bibliothèque pour les trier réellement par leurs numéros de ligne).
Donc, faire en sorte que ces méthodes soient statiques est la seule solution raisonnable.
Voici un exemple:
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");
}
}
Quelles impressions:
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
Comme vous pouvez le voir, chacun des tests est exécuté avec sa propre instance. Ce que fait JUnit est fondamentalement le même que celui-ci:
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();
La réponse courte est la suivante: il n'y a aucune bonne raison pour que ce soit statique.
En fait, le rendre statique pose toutes sortes de problèmes si vous utilisez Junit pour exécuter des tests d'intégration DAO basés sur DBUnit. L'exigence statique interfère avec l'injection de dépendances, l'accès au contexte d'application, la gestion des ressources, la journalisation et tout ce qui dépend de "getClass".
la source
@PostConstruct
pour la configuration et@AfterClass
pour le démontage et j'ignore complètement les annotations statiques de Junit. Pour les tests DAO, j'ai ensuite écrit ma propreTestCaseDataLoader
classe que j'appelle à partir de ces méthodes.@PostConstruct
et@AfterClass
se comporte de la même manière que@Before
et@After
. En fait, vos méthodes seront appelées pour chaque méthode de test et pas une seule fois pour toute la classe (comme Esko Luontola le déclare dans sa réponse, une instance de classe est créée pour chaque méthode de test). Je ne vois pas l'utilité de votre solution donc (sauf si je rate quelque chose)La documentation de JUnit semble rare, mais je devine: peut-être que JUnit crée une nouvelle instance de votre classe de test avant d'exécuter chaque cas de test, donc la seule façon pour que votre état "fixture" persiste à travers les exécutions est de le rendre statique, ce qui peut être appliquée en vous assurant que votre fixtureSetup (méthode @BeforeClass) est statique.
la source
Bien que cela ne réponde pas à la question initiale. Il répondra au suivi évident. Comment créer une règle qui fonctionne avant et après un cours et avant et après un test.
Pour y parvenir, vous pouvez utiliser ce modèle:
Avant (Classe), JPAConnection crée la connexion une fois après (Classe), il la ferme.
getEntityManger
renvoie une classe interne deJPAConnection
qui implémente EntityManager de jpa et peut accéder à la connexion à l'intérieur dujpaConnection
. Avant (test), il commence une transaction après (test), il l'annule à nouveau.Ce n'est pas thread-safe mais peut être fait pour l'être.
Code sélectionné de
JPAConnection.class
la source
Il semble que JUnit crée une nouvelle instance de la classe de test pour chaque méthode de test. Essayez ce code
La sortie est 0 0 0
Cela signifie que si la méthode @BeforeClass n'est pas statique, elle devra être exécutée avant chaque méthode de test et il n'y aurait aucun moyen de différencier la sémantique de @Before et @BeforeClass
la source
il existe deux types d'annotations:
donc @BeforeClass doit être déclaré statique car il est appelé une fois. Vous devez également considérer qu'être statique est le seul moyen d'assurer une bonne propagation de "l'état" entre les tests (le modèle JUnit impose une instance de test par @Test) et, puisque en Java seules les méthodes statiques peuvent accéder aux données statiques ... @BeforeClass et @ AfterClass ne peut être appliqué qu'aux méthodes statiques.
Cet exemple de test devrait clarifier l'utilisation de @BeforeClass par rapport à @Before:
production:
la source
Selon JUnit 5, il semble que la philosophie de création stricte d'une nouvelle instance par méthode de test ait été quelque peu assouplie. Ils ont ajouté une annotation qui instanciera une classe de test une seule fois. Cette annotation permet donc également aux méthodes annotées avec @ BeforeAll / @ AfterAll (les remplacements de @ BeforeClass / @ AfterClass) d'être non statiques. Donc, une classe de test comme celle-ci:
imprimerait:
Ainsi, vous pouvez réellement instancier des objets une fois par classe de test. Bien sûr, cela fait de votre propre responsabilité d'éviter la mutation des objets instanciés de cette façon.
la source
Pour résoudre ce problème, changez simplement la méthode
à
et tout ce qui est défini dans cette méthode à
static
.la source