web-dev-qa-db-fra.com

Comment savoir si le code est exécuté dans un test JUnit ou non?

Dans mon code, je dois effectuer certains correctifs uniquement lorsqu'il est exécuté dans un test JUnit. Comment savoir si le code est exécuté dans un test JUnit ou non? Y a-t-il quelque chose comme JUnit.isRunning () == true? 

46
Dr. Max Völkel

Tout d'abord, ceci n'est probablement pas une bonne idée. Vous devriez être en train de tester le code de production réel, pas un code légèrement différent. 

Si vous voulez vraiment faire cela, vous pouvez regarder le stacktrace, mais puisque vous changez votre programme pour cela de toute façon, vous pourriez aussi bien introduire un nouveau champ booléen statique isUnitTesting dans votre code et laisser JUnit définir ceci à true. Rester simple.

23
Thilo

Ce serait peut-être une bonne idée si vous voulez décider par programme quel "profil" exécuter. Pensez aux profils de printemps pour la configuration. Dans les tests d'intégration, vous pouvez tester une autre base de données. 

Voici le code testé qui fonctionne

public static boolean isJUnitTest() {
    StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
    List<StackTraceElement> list = Arrays.asList(stackTrace);
    for (StackTraceElement element : list) {
        if (element.getClassName().startsWith("org.junit.")) {
            return true;
        }           
    }
    return false;
}
43
Janning

Beaucoup de personnes sur ce fil disent qu'il est une mauvaise idée que le code s'exécute légèrement différemment sous JUnit. Je suis généralement d’accord, mais je pense qu’il existe quelques exceptions.

Par exemple, je rédige actuellement des tests INTEGRATION (par opposition à Unit) pour une application qui se connecte à une base de données.

Ces tests de réception doivent souvent réinitialiser complètement la base de données avec des données de test spécifiques.

Évidemment, je ne veux pas que cela soit JAMAIS, JAMAIS effectué sur une base de données de production réelle, car cela pourrait effacer complètement les données de production utiles.

Le moyen le plus simple de garantir que cela n'arrivera jamais est d'empêcher le code de se connecter à une base de données de production lorsqu'il est exécuté sous JUnit. Cela peut à son tour être fait si, par exemple, la fabrique qui génère une connexion peut indiquer qu'elle fonctionne sous JUnit et, dans ce cas, renverra une connexion null à moins que la base de données à laquelle nous essayons de vous connecter ait un nom connu être une base de données de test (ex: "testdatabase").

16
user3022950

Je peux trouver une justification à cela, c'est-à-dire lorsque vous souhaitez fournir du code dans une classe de production pour faciliter les tests. Cela serait similaire à l'assertion Java, qui ne s'applique que lorsque l'indicateur de débogage est défini.

Quelque chose comme ça:

Object debugState() {
    // This is only meant to be called when testing
    if (!JUnit.isRunning()) {
        throw new IllegalStateException("Not in a test!");
    }
    // Now compute possibly costly debug information
    // not to be used in production
    Object state = ...
}
10
Jaime Saiz

Si vous faites les choses différemment parce que vous effectuez un test unitaire, vous niez l'objectif d'un test unitaire. Un test unitaire est censé fonctionner exactement comme le ferait une production (à l'exception de la configuration et de la suppression de toutes les données nécessaires et de ce dont vous avez besoin ... mais cela est inclus dans le test JUnit lui-même et non dans votre code).

Cependant, si vous avez vraiment une bonne raison, examinons la pile et voyons si JUnit est là.

4
SOA Nerd

Que diriez-vous de vérifier si le Junit Jar est dans le classpath?

4
Snickers3192

Lorsque vous utilisez Spring, vous pouvez définir un bean contenant cette valeur.

En contexte d'application:

@Bean
public boolean isRunningTests() {
    return false;
}

Dans le contexte de l'application de test:

@Bean
public boolean isRunningTests() {
    return true;
}

Injectez la valeur à un composant Spring:

@Resource
private boolean isRunningTests;

private void someMethod() {
    if (isRunningTests()) {
        ....
1
Milanka

La solution la plus courte (le moins de code) consiste à avoir un indicateur global défini lorsque les tests sont en cours d'exécution pas. Vous pouvez ensuite le définir une fois dans votre main() (ou un point d’entrée similaire) au lieu de le définir de manière répétée dans les méthodes de configuration de toutes les classes de test. Cela fonctionnera tant qu'il n'y aura pas d'autre moyen d'entrer le code (pas d'alternative main).

La deuxième solution la plus courte est d’analyser la pile d’appels à la recherche du paquet Junit, comme dans réponse de Janning . Cela fonctionnera aussi longtemps que junit ne se cache pas derrière une autre bibliothèque et un exécuteur.

L'injection de dépendance fonctionnera également, mais dans ce cas, il s'agit simplement d'une manière élégante de définir ce qui est essentiellement un indicateur global.

0
Robert Važan

Pour distinguer test ou non test, vous pouvez toujours définir une propriété ou une valeur spéciale dans application-test.properties. 

0
Meir G.

Cela a fonctionné pour moi:

private Boolean isRunningTest = null;

private boolean isRunningTest() {
    if (isRunningTest == null) {
        isRunningTest = true;
        try {
            Class.forName("org.junit.Test");
        } catch (ClassNotFoundException e) {
            isRunningTest = false;
        }
    }
    return isRunningTest;
}

Il peut être utilisé dans les tests Maven, ainsi qu'à l'intérieur de l'EDI Eclipse, à condition que junit soit inclus en tant que dépendance avec le champ "test", par exemple:

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>${junit.version}</version>
    <scope>test</scope>
</dependency>
0
Andrea M