Junit - exécuter la méthode de configuration une fois
119
J'ai mis en place une classe avec quelques tests et plutôt que d'utiliser, @Beforej'aimerais avoir une méthode de configuration qui ne s'exécute qu'une seule fois avant tous les tests. Est-ce possible avec Junit 4.8?
Bien que je sois d'accord avec @assylias, l'utilisation @BeforeClassest une solution classique, ce n'est pas toujours pratique. La méthode annotée avec @BeforeClassdoit être statique. C'est très gênant pour certains tests qui nécessitent une instance de cas de test. Par exemple, des tests basés sur Spring qui @Autowiredfonctionnent avec des services définis dans un contexte de printemps.
Dans ce cas, j'utilise personnellement la setUp()méthode régulière annotée avec @Beforeannotation et gère mon drapeau personnalisé static(!) boolean:
privatestaticboolean setUpIsDone =false;.....@Beforepublicvoid setUp(){if(setUpIsDone){return;}// do the setup
setUpIsDone =true;}
Ajoutant au commentaire de Kenny Cason sur la raison pour laquelle il doit être statique. Il doit être statique car JUnit instancie une nouvelle instance de la classe de test pour chaque méthode @Test. La variable d'instance sera réinitialisée à sa valeur par défaut (false) pour chaque instance si elle n'est pas statique. Voir pour plus d'informations: martinfowler.com/bliki/JunitNewInstance.html
dustin.schultz
2
Cela fonctionne sauf dans le cas où la setUp()méthode est dans une superclasse - ont publié une réponse ci-dessous pour tenter de résoudre ce problème.
Steve Chambers
4
J'hésite à dire cela à quelqu'un avec un représentant de 84k, mais BeforeClass ne répond pas en fait à la question: BeforeClass est exécuté au début de chaque classe de test. Mais l'OP en a demandé un qui s'exécute "une seule fois avant tous les tests". La solution que vous proposez pourrait le faire, mais vous devrez faire étendre toutes vos classes de test à une classe "CommonTest" ...
mike rodent
1
@mikerodent, IMHO OP a posé des questions sur tous les tests dans son cas de test, pas tous les tests dans l'ensemble. Donc, votre commentaire est moins pertinent. BTW, ne vous inquiétez pas de dire quoi que ce soit à qui que ce soit, même si sa réputation est élevée. Au moins c'est ce que je fais :). Et ma réputation était nettement inférieure en août 2012 lorsque j'ai répondu à la question.
AlexR
Cela ne fonctionne pas pour mon cas, les variables initialisées dans la configuration sont réinitialisées après chaque test, il est donc inutile de lancer une seule fois.
@mikerodent J'ai compris la question comme "tous les tests de la classe" - mais vous avez raison, ce n'est peut-être pas ce que l'OP voulait.
assylias
29
JUnit 5 a maintenant une annotation @BeforeAll:
Indique que la méthode annotée doit être exécutée avant toutes les méthodes @Test dans la classe ou la hiérarchie de classes actuelle; analogue à @BeforeClass de JUnit 4. Ces méthodes doivent être statiques.
Les annotations de cycle de vie de JUnit 5 semblent avoir enfin bien fait les choses! Vous pouvez deviner quelles annotations disponibles sans même regarder (par exemple @BeforeEach @AfterAll)
Il a le même problème @BeforeClass, il doit l'être static. La solution IMO @ AlexR est plus agréable.
zengr
@zengr a tendance à être d'accord avec vous: comme je l'ai dit à AlexR, sa solution nécessite que toutes les classes de test soient sous-classées à partir d'une classe CommonTest si elle n'est exécutée qu'une seule fois. Mais c'est aussi simple que possible, et à mon humble avis, vous ne devriez probablement pas utiliser une solution fournie par un framework «sophistiqué» lorsqu'un mécanisme simple est disponible dans le langage. Sauf s'il y a une bonne raison bien sûr. De plus, utiliser une chose simple comme la sienne, avec un bon nom de type «fait ce qu'il dit sur l'étain», aide à la lisibilité.
mike rodent
Cela dit, encore une fois à mon humble avis, il semble bien plus justifié d'avoir une annotation «AfterAll»: il serait très difficile et inventé de concevoir un mécanisme pour détecter quand tous les tests ont été effectués. Inversement, bien sûr, les puristes vont probablement dire que vous ne devriez jamais avoir à faire un "nettoyage final", c'est-à-dire que chaque "tearDown" devrait laisser toutes les ressources dans un état impeccable ... et ils ont probablement raison!
mike rodent
Est-ce que cela fonctionne avec Maven où il y a plusieurs modules, chacun avec ses tests?
Mark Boon
@mike rodent, dans mon cas, la configuration et la suppression de fichiers de test dans le système de fichiers avant / après chaque test semble entraîner des blocages sur les fichiers. Pour l'instant, je suis arrivé indépendamment à la solution d'AlexR pour une configuration unique. J'ai deux drapeaux statiques, déjà configurés et sales. setup () appelle cleanup () si un état sale est détecté initialement, ou si un échec de configuration conduit à un état sale. Pour nettoyer après avoir exécuté des tests, je les réexécute. Désordonné, pas idéal du tout, pas dans notre processus de construction. Toujours à la recherche d'un meilleur moyen (jUnit 4.12).
Rebeccah
9
Lorsqu'il setUp()est dans une superclasse de la classe de test (par exemple AbstractTestBaseci-dessous), la réponse acceptée peut être modifiée comme suit:
publicabstractclassAbstractTestBase{privatestaticClass<?extendsAbstractTestBase> testClass;.....publicvoid setUp(){if(this.getClass().equals(testClass)){return;}// do the setup - once per concrete test class.....
testClass =this.getClass();}}
Cela devrait fonctionner pour une seule setUp()méthode non statique mais je suis incapable de produire un équivalent pour tearDown()sans m'égarer dans un monde de réflexion complexe ... Bounty pointe vers tous ceux qui le peuvent!
Edit:
Je viens de découvrir lors du débogage que la classe est également instanciée avant chaque test. Je suppose que l'annotation @BeforeClass est la meilleure ici.
Vous pouvez également configurer sur le constructeur, la classe de test est une classe après tout. Je ne sais pas si c'est 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.
avec @BeforeAllMethods/ @AfterAllMethodsannotation, 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.
classe publique TestCaseExtended étend TestCase {booléen statique privé isInitialized = false; private static TestCaseExtended caseExtended; private int serId; @Override public void setUp () lève l'exception {super.setUp (); if (! isInitialized) {caseExtended = new TestCaseExtended (); caseExtended.loadSaveNewSerId (); caseExtended.emptyTestResultsDirectory (); isInitialized = true; }}
Obi Two
0
Si vous ne voulez pas forcer une déclaration d'une variable qui est définie et vérifiée à chaque sous-test, l'ajout de ceci à un SuperTest pourrait faire:
Ajoutez à votre classe abstraite de base (je veux dire la classe abstraite où vous initialisez votre pilote dans méthode setUpDriver () ) cette partie de code:
privatestaticboolean started =false;static{if(!started){
started =true;try{
setUpDriver();//method where you initialize your driver}catch(MalformedURLException e){}}}
Et maintenant, si vos cours de test étend de base classe abstraite -> setUpDriver () méthode sera exécutée avant la première @Test seulement UNE fois par course.
Utilisez la méthode @PostConstruct de Spring pour effectuer tout le travail d'initialisation et cette méthode s'exécute avant l'exécution de tout @Test
Réponses:
Bien que je sois d'accord avec @assylias, l'utilisation
@BeforeClass
est une solution classique, ce n'est pas toujours pratique. La méthode annotée avec@BeforeClass
doit être statique. C'est très gênant pour certains tests qui nécessitent une instance de cas de test. Par exemple, des tests basés sur Spring qui@Autowired
fonctionnent avec des services définis dans un contexte de printemps.Dans ce cas, j'utilise personnellement la
setUp()
méthode régulière annotée avec@Before
annotation et gère mon drapeau personnaliséstatic
(!)boolean
:la source
setUp()
méthode est dans une superclasse - ont publié une réponse ci-dessous pour tenter de résoudre ce problème.Vous pouvez utiliser l'
BeforeClass
annotation :la source
TheClassYouWant.class
place de votre appel getClass ()? Ceci est Java réelle:String.class.getName()
.JUnit 5 a maintenant une annotation @BeforeAll:
Les annotations de cycle de vie de JUnit 5 semblent avoir enfin bien fait les choses! Vous pouvez deviner quelles annotations disponibles sans même regarder (par exemple @BeforeEach @AfterAll)
la source
@BeforeClass
, il doit l'êtrestatic
. La solution IMO @ AlexR est plus agréable.Lorsqu'il
setUp()
est dans une superclasse de la classe de test (par exempleAbstractTestBase
ci-dessous), la réponse acceptée peut être modifiée comme suit:Cela devrait fonctionner pour une seule
setUp()
méthode non statique mais je suis incapable de produire un équivalent pourtearDown()
sans m'égarer dans un monde de réflexion complexe ... Bounty pointe vers tous ceux qui le peuvent!la source
Edit: Je viens de découvrir lors du débogage que la classe est également instanciée avant chaque test. Je suppose que l'annotation @BeforeClass est la meilleure ici.
Vous pouvez également configurer sur le constructeur, la classe de test est une classe après tout. Je ne sais pas si c'est une mauvaise pratique car presque toutes les autres méthodes sont annotées, mais cela fonctionne. Vous pouvez créer un constructeur comme ça:
Le ctor sera appelé avant les tests car ils ne sont pas statiques.
la source
Essayez cette solution: https://stackoverflow.com/a/46274919/907576 :
avec
@BeforeAllMethods
/@AfterAllMethods
annotation, 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.la source
Ma sale solution est:
Je l'utilise comme base de base pour tous mes testCases.
la source
Si vous ne voulez pas forcer une déclaration d'une variable qui est définie et vérifiée à chaque sous-test, l'ajout de ceci à un SuperTest pourrait faire:
la source
J'ai résolu ce problème comme ceci:
Ajoutez à votre classe abstraite de base (je veux dire la classe abstraite où vous initialisez votre pilote dans méthode setUpDriver () ) cette partie de code:
Et maintenant, si vos cours de test étend de base classe abstraite -> setUpDriver () méthode sera exécutée avant la première @Test seulement UNE fois par course.
la source
Utilisez la méthode @PostConstruct de Spring pour effectuer tout le travail d'initialisation et cette méthode s'exécute avant l'exécution de tout @Test
la source