Existe-t-il des pratiques recommandées pour que Junit exécute une fonction une fois dans un fichier de test, et cela ne doit pas non plus être statique.
comme @BeforeClass
sur une fonction non statique?
Voici une solution laide:
@Before void init(){
if (init.get() == false){
init.set(true);
// do once block
}
}
eh bien c'est quelque chose que je ne veux pas faire, et je cherche une solution intégrée junit.
Si vous ne souhaitez pas configurer d'initialisateurs statiques pour une initialisation unique et que vous ne souhaitez pas utiliser JUnit, consultez TestNG. TestNG prend en charge une initialisation unique non statique avec une variété d’options de configuration, toutes utilisant des annotations.
Dans TestNG, cela équivaudrait à:
@org.testng.annotations.BeforeClass
public void setUpOnce() {
// One time initialization.
}
Pour le démontage,
@org.testng.annotations.AfterClass
public void tearDownOnce() {
// One time tear down.
}
Pour l'équivalent TestNG de @Before
et @After
de JUnit 4, vous pouvez utiliser @BeforeMethod
et @AfterMethod
respectivement.
Utiliser un constructeur vide est la solution la plus simple. Vous pouvez toujours remplacer le constructeur dans la classe étendue.
Mais ce n'est pas optimal avec tout l'héritage. C'est pourquoi JUnit 4 utilise plutôt des annotations.
Une autre option consiste à créer une méthode d'assistance dans une classe factory/util et à laisser cette méthode effectuer le travail.
Si vous utilisez Spring, vous devriez envisager d'utiliser l'annotation @TestExecutionListeners
. Quelque chose comme ce test:
@RunWith(SpringJUnit4ClassRunner.class)
@TestExecutionListeners({CustomTestExecutionListener.class,
DependencyInjectionTestExecutionListener.class})
@ContextConfiguration("test-config.xml")
public class DemoTest {
La variable AbstractTestExecutionListener
de Spring contient par exemple cette méthode vide que vous pouvez remplacer:
public void beforeTestClass(TestContext testContext) throws Exception {
/* no-op */
}
Une simple déclaration si semble plutôt bien fonctionner:
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:test-context.xml"})
public class myTest {
public static boolean dbInit = false;
@Autowired
DbUtils dbUtils;
@Before
public void setUp(){
if(!dbInit){
dbUtils.dropTables();
dbUtils.createTables();
dbInit = true;
}
}
...
Utilisez facilement les annotations @BeforeAllMethods
@AfterAllMethods
pour exécuter une méthode dans le contexte de l'instance (non statique), où toutes les valeurs injectées seront disponibles.
Il existe une bibliothèque de tests spéciale pour cela:
https://mvnrepository.com/artifact/org.bitbucket.radistao.test/before-after-spring-test-runner/0.1.0
https://bitbucket.org/radistao/before-after-spring-test-runner/
La seule limitation: ne fonctionne que pour les tests _/Spring.
(Je suis le développeur de cette bibliothèque de tests)
Il suffit d'utiliser @BeforeClass
:
@BeforeClass
public static void init() {
}
init
n'a pas de sens d'être non statique car chaque test est exécuté dans une instance distincte. L'instance Sur laquelle init
est exécutée ne correspond à l'instance d'aucun test.
La seule raison pour laquelle vous souhaitez peut-être qu'il soit non statique est de le remplacer dans les sous-classes, mais vous pouvez le faire .__ avec des méthodes statiques également. Utilisez simplement le même nom, et seule la méthode init
de la sous-classe sera appelée.
Je n'ai jamais essayé, mais vous pouvez peut-être créer un constructeur sans argument et appeler votre fonction à partir de là?
L'article discute de 2 très bonnes solutions à ce problème:
UPDATE: Veuillez consulter le commentaire de Cherry pour expliquer pourquoi la suggestion ci-dessous est erronée. (Je garde la réponse ici plutôt que de le supprimer car le commentaire peut fournir des informations utiles) information aux autres sur les raisons pour lesquelles cela ne fonctionne pas .)
Une autre option à considérer si l’utilisation de l’injection de dépendance (par exemple Spring) est @PostConstruct
. Cela garantira que l'injection de dépendance est complète, ce qui ne serait pas le cas chez un constructeur:
_@PostConstruct public void init() { // One-time initialization... }
_