web-dev-qa-db-fra.com

Junit - lance la méthode d'installation une fois

J'ai configuré une classe avec quelques tests et plutôt que d'utiliser @Before, j'aimerais avoir une méthode d'installation qui ne s'exécute qu'une fois avant tous les tests. Est-ce possible avec Junit 4.8?

102
Bober02

Bien que je convienne avec @assylias que l’utilisation de @BeforeClass est une solution classique, elle n’est pas toujours pratique. La méthode annotée avec @BeforeClass doit être statique. Cela est très gênant pour certains tests nécessitant une instance de cas de test. Par exemple, les tests basés sur Spring qui utilisent @Autowired pour travailler avec des services définis dans un contexte Spring. 

Dans ce cas, j'utilise personnellement la méthode setUp() régulière annotée avec l'annotation @Before et gère mon indicateur boolean personnalisé:

private static boolean setUpIsDone = false;
.....
public void setUp() {
    if (setUpIsDone) {
        return;
    }
    // do the setup
    setUpIsDone = true;
}
179
AlexR

Vous pouvez utiliser l'annotation BeforeClass :

@BeforeClass
public static void setUpClass() {
    //executed only once, before the first test
}
82
assylias

JUnit 5 a maintenant une annotation @BeforeAll:

Indique que la méthode annotée doit être exécutée avant tout @Test les méthodes de la classe ou de la hiérarchie de classes actuelle; analogue à JUnit @ BeeClass de 4. De telles méthodes doivent être statiques.

Les annotations sur le cycle de vie de JUnit 5 semblent enfin avoir bien fonctionné! Vous pouvez deviner les annotations disponibles sans même regarder (par exemple, @BeforeEach @AfterAll).

24
Brian

Lorsque setUp() est dans une superclasse de la classe de test, la réponse acceptée peut être modifiée comme suit:

public abstract class AbstractTestBase {
    private static Class<? extends AbstractTestBase> testClass;
    .....
    public void setUp() {
        if (this.getClass().equals(testClass)) {
            return;
        }

        // do the setup - once per concrete test class
        .....
        testClass = this.getClass();
    }
}

Cela devrait fonctionner pour une seule méthode setUp() non statique, mais je suis incapable de produire un équivalent pour tearDown() sans m'égarer dans un monde de réflexion complexe ... Bounty est destiné à quiconque le peut!

7
Steve Chambers

Edit: Je viens de découvrir en déboguant que la classe est instanciée avant chaque test aussi . Je suppose que l'annotation @BeforeClass est la meilleure ici.

Vous pouvez également configurer le constructeur, la classe de test est une classe après tout ... Je ne suis pas sûre que ce soit une mauvaise pratique car presque toutes les autres méthodes sont annotées, mais cela fonctionne. Vous pouvez créer un constructeur comme ça:

public UT () {
    // initialize once here
}
@Test
// Some test here...

Le ctor sera appelé avant les tests car ils ne sont pas statiques.

2
user5692355

Si vous ne voulez pas forcer la déclaration d'une variable définie et vérifiée pour chaque sous-test, ajouter ceci à un SuperTest peut faire: 

public abstract class SuperTest {

    private static final ConcurrentHashMap<Class, Boolean> INITIALIZED = new ConcurrentHashMap<>();
    protected final boolean initialized() {
        final boolean[] absent = {false};
        INITIALIZED.computeIfAbsent(this.getClass(), (klass)-> {
            return absent[0] = true;
        });
        return !absent[0];
    }
}



public class SubTest extends SuperTest {
    @Before
    public void before() {
        if ( super.initialized() ) return;

         ... magic ... 
    }

}
0
momomo

J'ai résolu ce problème comme ceci:

Ajoutez à votre classe abstraite Base (je veux dire une classe abstraite dans laquelle vous initialisez votre pilote dans la méthode setUpDriver () ), cette partie de code:

private static boolean started = false;
static{
    if (!started) {
        started = true;
        try {
            setUpDriver();  //method where you initialize your driver
        } catch (MalformedURLException e) {
        }
    }
}

Et maintenant, si vos classes de test vont s'étendre de la méthode Base abstraite -> setUpDriver () avant la première @ Test seulement UN temps par cycle.

0
Sergii

Ma solution sale est:

public class TestCaseExtended extends TestCase {

    private boolean isInitialized = false;
    private int serId;

    @Override
    public void setUp() throws Exception {
        super.setUp();
        if(!isInitialized) {
            loadSaveNewSerId();
            emptyTestResultsDirectory();
            isInitialized = true;
        }
    }

   ...

}

Je l'utilise comme base pour tous mes tests.

0
Obi Two

Essayez cette solution: https://stackoverflow.com/a/46274919/907576 :

avec l'annotation @BeforeAllMethods/@AfterAllMethods, vous pouvez exécuter n'importe quelle méthode de la classe Test dans un contexte d'instance où toutes les valeurs injectées sont disponibles.

0
radistao