J'essaie de pré-configurer et démonter un ensemble de tests d'intégration, en utilisant jUnit 4.4 pour exécuter les tests. Le démontage doit être exécuté de manière fiable. J'ai d'autres problèmes avec TestNG, donc je cherche à porter sur jUnit. Quels crochets sont disponibles pour exécution avant l'exécution des tests et une fois tous les tests terminés?
Remarque: nous utilisons maven 2 pour notre build. J'ai essayé d'utiliser le pre-
& post-integration-test
phases, mais, si un test échoue, maven s'arrête et ne s'exécute pas post-integration-test
, ce qui n'est d'aucune aide.
Oui, il est possible d'exécuter de manière fiable les méthodes de configuration et de démontage avant et après tout test dans une suite de tests. Permettez-moi de démontrer dans le code:
package com.test;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
@RunWith(Suite.class)
@SuiteClasses({Test1.class, Test2.class})
public class TestSuite {
@BeforeClass
public static void setUp() {
System.out.println("setting up");
}
@AfterClass
public static void tearDown() {
System.out.println("tearing down");
}
}
Ainsi, votre classe Test1 ressemblerait à quelque chose comme:
package com.test;
import org.junit.Test;
public class Test1 {
@Test
public void test1() {
System.out.println("test1");
}
}
... et vous pouvez imaginer que Test2 se ressemble. Si vous exécutiez TestSuite, vous obtiendrez:
setting up
test1
test2
tearing down
Vous pouvez donc voir que la configuration/démontage ne s'exécute qu'avant et après tous les tests, respectivement.
Le hic: cela ne fonctionne que si vous exécutez la suite de tests et que vous n'exécutez pas Test1 et Test2 en tant que tests JUnit individuels. Vous avez mentionné que vous utilisez maven, et le plugin maven surefire aime exécuter des tests individuellement, et ne fait pas partie d'une suite. Dans ce cas, je recommanderais de créer une superclasse que chaque classe de test étend. La superclasse contient ensuite les méthodes annotées @BeforeClass et @AfterClass. Bien que pas aussi propre que la méthode ci-dessus, je pense que cela fonctionnera pour vous.
En ce qui concerne le problème des tests ayant échoué, vous pouvez définir maven.test.error.ignore afin que la construction se poursuive sur les tests ayant échoué. Ce n'est pas recommandé comme pratique continue, mais cela devrait vous permettre de fonctionner jusqu'à ce que tous vos tests réussissent. Pour plus de détails, consultez la documentation de maven surefire .
Un de mes collègues a suggéré ce qui suit: vous pouvez utiliser un RunListener personnalisé et implémenter la méthode testRunFinished (): http://junit.sourceforge.net/javadoc/org/junit/runner/notification/RunListener.html# testRunFinished (org.junit.runner.Result)
Pour enregistrer RunListener, il suffit de configurer le plugin surefire comme suit: http://maven.Apache.org/surefire/maven-surefire-plugin/examples/junit.html section "Utilisation d'écouteurs et de reporters personnalisés"
Cette configuration doit également être choisie par le plug-in à sécurité intégrée. Cette solution est excellente car vous n'avez pas à spécifier de suites, de classes de test de recherche ou de tout cela - elle permet à Maven de faire sa magie, en attendant que tous les tests se terminent.
Vous pouvez utiliser @ annotation ClassRule dans JUnit 4.9 + comme j'ai décrit dans une réponse une autre question .
En utilisant des annotations, vous pouvez faire quelque chose comme ceci:
import org.junit.*;
import static org.junit.Assert.*;
import Java.util.*;
class SomethingUnitTest {
@BeforeClass
public static void runBeforeClass()
{
}
@AfterClass
public static void runAfterClass()
{
}
@Before
public void setUp()
{
}
@After
public void tearDown()
{
}
@Test
public void testSomethingOrOther()
{
}
}
Ici, nous
À condition que tous vos tests puissent étendre une classe "technique" et soient dans le même package, vous pouvez faire une petite astuce:
public class AbstractTest {
private static int nbTests = listClassesIn(<package>).size();
private static int curTest = 0;
@BeforeClass
public static void incCurTest() { curTest++; }
@AfterClass
public static void closeTestSuite() {
if (curTest == nbTests) { /*cleaning*/ }
}
}
public class Test1 extends AbstractTest {
@Test
public void check() {}
}
public class Test2 extends AbstractTest {
@Test
public void check() {}
}
Sachez que cette solution présente de nombreux inconvénients:
Pour information: listClassesIn () => Comment trouvez-vous toutes les sous-classes d'une classe donnée en Java?
Quant à "Remarque: nous utilisons maven 2 pour notre build. J'ai essayé d'utiliser les phases de test pré-et post-intégration de maven, mais, si un test échoue, maven s'arrête et n'exécute pas le test post-intégration , ce qui n'est pas utile. "
vous pouvez essayer le plug-in à la place, je pense qu'il a la possibilité de garantir le nettoyage indépendamment de la configuration ou de l'état de l'étape intermédiaire
Si vous ne voulez pas créer une suite et devez lister toutes vos classes de test, vous pouvez utiliser la réflexion pour trouver le nombre de classes de test dynamiquement et décompter dans une classe de base @AfterClass pour faire le tearDown une seule fois:
public class BaseTestClass
{
private static int testClassToRun = 0;
// Counting the classes to run so that we can do the tear down only once
static {
try {
Field field = ClassLoader.class.getDeclaredField("classes");
field.setAccessible(true);
@SuppressWarnings({ "unchecked", "rawtypes" })
Vector<Class> classes = (Vector<Class>) field.get(BlockJUnit4ClassRunner.class.getClassLoader());
for (Class<?> clazz : classes) {
if (clazz.getName().endsWith("Test")) {
testClassToRun++;
}
}
} catch (Exception ignore) {
}
}
// Setup that needs to be done only once
static {
// one time set up
}
@AfterClass
public static void baseTearDown() throws Exception
{
if (--testClassToRun == 0) {
// one time clean up
}
}
}
Si vous préférez utiliser @BeforeClass au lieu des blocs statiques, vous pouvez également utiliser un indicateur booléen pour effectuer le comptage de réflexion et tester la configuration une seule fois au premier appel. J'espère que cela aide quelqu'un, il m'a fallu un après-midi pour trouver une meilleure façon que d'énumérer toutes les classes dans une suite.
Il ne vous reste plus qu'à étendre cette classe à toutes vos classes de test. Nous avions déjà une classe de base pour fournir des éléments communs à tous nos tests, donc c'était la meilleure solution pour nous.
L'inspiration vient de cette SO réponse https://stackoverflow.com/a/37488620/5930242
Si vous ne voulez pas étendre cette classe partout, cette dernière réponse SO pourrait faire ce que vous voulez.
Étant donné que maven-surefire-plugin n'exécute pas la classe Suite en premier mais traite les classes de suite et de test de la même manière, nous pouvons donc configurer le plugin comme ci-dessous pour activer uniquement les classes de suite et désactiver tous les tests. Suite exécutera tous les tests.
<plugin>
<groupId>org.Apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.5</version>
<configuration>
<includes>
<include>**/*Suite.Java</include>
</includes>
<excludes>
<exclude>**/*Test.Java</exclude>
<exclude>**/*Tests.Java</exclude>
</excludes>
</configuration>
</plugin>
La seule façon, je pense, d'obtenir les fonctionnalités que vous souhaitez serait de faire quelque chose comme
import junit.framework.Test;
import junit.framework.TestResult;
import junit.framework.TestSuite;
public class AllTests {
public static Test suite() {
TestSuite suite = new TestSuite("TestEverything");
//$JUnit-BEGIN$
suite.addTestSuite(TestOne.class);
suite.addTestSuite(TestTwo.class);
suite.addTestSuite(TestThree.class);
//$JUnit-END$
}
public static void main(String[] args)
{
AllTests test = new AllTests();
Test testCase = test.suite();
TestResult result = new TestResult();
setUp();
testCase.run(result);
tearDown();
}
public void setUp() {}
public void tearDown() {}
}
J'utilise quelque chose comme ça dans Eclipse, donc je ne sais pas comment il est portable en dehors de cet environnement
Pour autant que je sache, il n'existe aucun mécanisme pour le faire dans JUnit, mais vous pouvez essayer de sous-classer Suite et de remplacer la méthode run () avec une version qui fournit des hooks.