Junit4: Ajouter des annotations d'exécution paramétrée avant et après

Créé le 16 nov. 2009  ·  39Commentaires  ·  Source: junit-team/junit4

Actuellement, il n'existe aucun moyen simple d'invoquer une méthode avant ou après l'exécution d'une instance Parameterized.

Autrement dit, avec @BeforeClass et @AfterClass , il devrait y avoir @BeforeParameterRun @AfterParameterRun. Chacun se déclenche avant/après l'exécution d'une instance paramétrée.

feature parameterized

Commentaire le plus utile

les gars, "après / avant" pour chaque exécution paramétrée serait très utile.

Tous les 39 commentaires

Que diriez-vous d'un paramètre sur l'annotation @Before elle-même : @Before(true) ou @Before(onEachParameter = true). Faux par défaut, bien sûr.

L'objectif de cette requête est d'avoir un emplacement pour placer le code qui s'exécute avant et après l'exécution d'une exécution de paramètre. Pas avant chaque test dans une exécution de paramètre donnée. Ainsi, l'ordre serait BP BT T1p1 AT BT T2p1 AT BT T3p1 AT AP BP BT T1p2 AT BT T2p2 AT ... où

  • BP est la méthode d'exécution des paramètres avant @BeforeParameterRun
  • BT est la méthode de test avant @Before
  • Txpy est le xième test, sur le paramètre y @Test par exemple T2P3 est le test 2 sur le paramètre 3
  • AT est la méthode de test après @After
  • AP est le paramètre après l'exécution @AfterParameterRun

Je l'ai fait implémenter sur mon github, mais j'ai dû le supprimer en raison de problèmes avec mon employeur. J'ai envoyé un pull à David Saff et il l'a inclus dans sa branche, mais il a été retiré plus tard. Je chercherai le numéro de révision où le code a été inclus après ce message.

On dirait que la fusion a eu lieu vers un arbre de dsaff vers le 3 avril 2009. Dans les commentaires, vous pouvez voir une fusion de bigmikef. Il est obsolète, mais fonctionnait à l'époque.

les gars, "après / avant" pour chaque exécution paramétrée serait très utile.

Cela peut être fait à l'aide de règles, en particulier ExternalResource. Les méthodes implémentées sont appelées pour chaque paramètre :

@RunWith(Parameterized.class)
public class ParameterRuleTest {
    @Parameters()
    public static Iterable<Object[]> data() {
        return Arrays.asList(new Object[]{}, new Object[]{});
    }

    <strong i="6">@Rule</strong>
    public ExternalResource externalResource = new ExternalResource() {
        protected void before() throws Throwable { System.out.println("before"); }
        protected void after() { System.out.println("after"); }
    };

    <strong i="7">@Test</strong> public void myTest1() { System.out.println("test"); }
}

Cela produit

test
after
before
test
after

Si cela est acceptable, veuillez fermer ce problème.

@matthewfarwell Je comprends peut-être mal votre réponse, mais dans l'exemple que vous avez fourni, cette règle s'exécuterait avant et après chaque test pour chaque instance créée par le coureur paramétré.

Ce que je pense que @bigmikef voulait, c'était la possibilité d'exécuter une méthode avant et après une fois pour chaque instance créée par le coureur paramétré. Je ne pense pas que @ClassRule puisse être utilisé dans ce cas car cela s'exécute dans un contexte statique et n'est exécuté qu'une seule fois pour toutes les instances paramétrées.

Cela ne me dérangerait pas de prendre l'initiative de mettre cela en œuvre car cela serait bénéfique dans mon projet actuel. Ma proposition ci-dessous :

Résumé de la mise en œuvre :

L'architecture traditionnelle de JUnit est une instance d'une classe Java par méthode de test. Afin de mettre en œuvre les exigences ci-dessus, je pense que le coureur Parameterized doit être modifié pour créer une instance Java pour chaque instance paramétrée.

La principale raison en est que la logique exécutée avant et après chaque exécution paramétrée est locale à la classe et non placée dans une portée globale avec un modificateur statique. Dans mon cas d'utilisation particulier, j'ai configuré et démonté ce qui nécessiterait l'utilisation de paramètres uniques à chaque instance paramétrée.

Ajouts / Modifications :

org.junit.runners.Parameterized

  • Ajoutez une nouvelle annotation nommée ParameterRule .
  • Ajoutez une nouvelle classe interne protégée qui étend TestClassRunnerForParameters nommée quelque chose comme SingleInstanceRunnerForParameters .
  • Instanciez TestClassRunnerForParameters ou SingleInstanceRunnerForParameters selon que ParameterRule existe ou non.

org.junit.runners.BlockJUnit4ClassRunner

  • Déplacez la création de l'objet de test hors de methodBlock . Fournissez plutôt l'objet de test en tant que paramètre.

    • La raison principale en est que les classes étendues pourraient passer leur propre instance dans methodBlock. Sinon, si quelqu'un veut étendre BlockJUnit4ClassRunner et conserver la plupart des fonctionnalités, il doit copier les méthodes suivantes : withRules , withMethodRules , withTestRules et getMethodRules

  • Si déplacer la création de l'objet de test hors de methodBlock n'est pas acceptable, changer les méthodes suivantes de private à protected réduirait la duplication de code :

    • withRules

    • withMethodRules

    • withTestRules

    • getMethodRules

org.junit.runners.Parameterized.SingleInstanceRunnerForParameters

  • Ajoutez une méthode nommée withParameterRules qui exécuterait les règles annotées par ParameterRule .
  • Exécutez withParameterRules dans une version surchargée de classBlock

S'il y a une préférence pour fournir un exemple de cette implémentation, je peux sur mon fork, mais je voulais discuter de la conception avant d'investir beaucoup de temps.

@coreyjv qu'est-ce qui ne va pas avec la réponse de @matthewfarwell ?

@ Tibor17 , voir ma réponse à sa réponse : https://github.com/KentBeck/junit/issues/45#issuecomment -11293228

Son implémentation est exécutée avant et après chaque méthode de test. Dans mon cas, ma configuration et mon démontage sont très coûteux, c'est pourquoi je souhaite l'exécuter avant et après chaque exécution paramétrée.

Par exemple, si j'ai une classe de test qui, lorsqu'elle est exécutée une fois avec une configuration commune (située dans un @ClassRule actuellement), la classe entière s'exécute et termine les tests en ~ 20 secondes. Cependant, si je déplace la configuration vers une règle au niveau de la méthode, il faut environ 240 secondes pour s'exécuter et se terminer. C'est juste pour une classe. Dans ma situation, cette augmentation du temps n'est pas acceptable.

Théoriquement, je pourrais placer tous mes tests dans une seule méthode pour émuler le comportement requis, mais je ne pense pas que ce soit une conception de test maintenable.

@ Tibor17 , je ne sais pas si les notifications sont envoyées sur les mises à jour, alors j'ai pensé que je ferais un autre commentaire.

@dsaff , des réflexions sur cette proposition ?

@coreyjv
Fondamentalement, ce que vous voulez, c'est quelque chose comme @BeforeParams et @AfterParams exécuté une seule fois dans le cycle de vie. Ai-je raison?

@ Tibor17 , essentiellement oui. Je pense que j'utiliserais une seule annotation permettant aux règles de s'exécuter.

Si j'utilisais la BeforeClass (BC) et l'AC, cela ressemblerait-il à ceci ?
BC BP BT T1p1 AT BT T2p1 AT BT T3p1 AT AP BP BT T1p2 AT BT T2p2 AT AC

@ Tibor17 , oui, je pense que ce que vous avez présenté est exact.

@coreyjv
Je pense que cette fonctionnalité que vous voulez pourrait être intéressante. Quel est votre vrai cas d'utilisation ?

@Tibor17
Je travaille actuellement sur la création d'une suite de tests de navigateur Web utilisant Selenium pour naviguer et inspecter le contenu de la page qui est transmis à JUnit pour l'exécution des cas de test.

Mes besoins ont abouti à une classe de test JUnit par page pour tester des éléments tels que :

  • Existe-t-il un champ ?
  • Est-ce en lecture seule ?
  • Le texte de l'étiquette est-il "X" ?

Ces pages peuvent être à n'importe quelle profondeur arbitraire dans l'application, j'ai donc mis la logique de navigation pour accéder à la page de destination dans une règle "avant" (actuellement @ClassRule). Idéalement, j'aimerais exécuter le même test avec des paramètres différents, qui sont lus et utilisés dans la "configuration". Ces paramètres seraient des éléments tels que l'identifiant de l'utilisateur et les informations d'identification du mot de passe et d'autres détails pertinents pour accéder à la page de destination.

Je vais citer une réponse précédente que j'ai écrite pour expliquer pourquoi je veux le faire par "cycle de vie":

Par exemple, si j'ai une classe de test qui, lorsqu'elle est exécutée une fois avec une configuration commune (située dans un @ClassRule actuellement), la classe entière s'exécute et termine les tests en ~ 20 secondes. Cependant, si je déplace la configuration vers une règle au niveau de la méthode, il faut environ 240 secondes pour s'exécuter et se terminer. C'est juste pour une classe. Dans ma situation, cette augmentation du temps n'est pas acceptable.

@coreyjv
signifie que les paramètres doivent également être visibles dans la configuration nouvellement annotée.
cela donne un aperçu complet des besoins.
Continue.

@ Tibor17 , corrigez les paramètres doivent être visibles dans la configuration. Quel genre d'éclaircissements ou de détails supplémentaires voudriez-vous que je fournisse ?

Je pense que l'aperçu et mes commentaires précédents donnent une bonne image de mon besoin (vous pouvez également voir la liste de diffusion) sans entrer dans les détails de l'application, ce qui, à mon avis, ajouterait une valeur limitée.

@coreyjv
Peut-être devriez-vous maintenant pousser un pull et y inclure également les personnes concernées par ce problème.

@Tibor17
Ça me va, je cherchais juste une première approbation sur la "conception" avant de continuer.

@coreyjv
J'ai hâte de voir un test qui décrit l'utilisation, même si l'impl du coureur est incomplète.
Que diraient les autres du test...

@Tibor17

Que diraient les autres du test...

Cherchez-vous que je publie un exemple de cours de test ? C'est vraiment assez ennuyeux car c'est comme n'importe quel autre test paramétré (où les paramètres sont lus à partir d'une base de données par exemple) et la configuration du "cycle de vie" serait utilisée à la place de la configuration @ClassRule ou @Rule . Comme je l'ai mentionné précédemment, un cas simple serait la configuration qui utilisait différentes combinaisons de noms d'utilisateur, de mots de passe et de rôles d'application.

Je ne pense pas que cela sorte de l'ordinaire. C'est juste dans ce cas que la configuration est extrêmement coûteuse à faire avant et après chaque méthode.

@coreyjv

Qu'en est-il de faire cela dans votre test

@BeforeParameter
public void static setup() { // flag this call in some variable and assert it's set }

@Tibor17
Comme je l'ai mentionné précédemment, cette configuration doit être paramétrée et serait unique pour chaque ensemble de paramètres renvoyés par @Parameters , donc je ne pense pas que cette approche fonctionnerait.

@coreyjv
Je pense que vous avez déjà un code d'instantané dans votre esprit.
Voulez-vous toujours en discuter ici ou souhaitez-vous ouvrir un pull ?

@Tibor17
Je vais le mettre ensemble et soumettre une pull request. Je ne le ferai peut-être qu'après le Nouvel An, mais je verrai ce que je peux faire. Merci pour la discussion j'apprécie.

Les pensées:

  1. Nous devrions faire en sorte que cela se produise, et je suis heureux de travailler avec les parties intéressées.
  2. Nous ne pouvons pas modifier la signature des méthodes protégées. Mais extraire un methodBlock protégé (méthode FrameworkMethod, test d'objet) semble être une très bonne idée.
  3. Lors de l'écriture de l'interface ParameterRule, gardez à l'esprit que je pense que nous devons améliorer le fonctionnement de Rule et ClassRule. https://docs.google.com/document/d/1B6Z45BSGsY08rZqe2KUZTJ3RVsnUE1-HcXjl5MFm9ls/edit aide à expliquer où j'aimerais voir les choses avancer : ParameterRule pourrait particulièrement bénéficier de ce type d'approche de fabrique de règles, car cela permettrait une réutilisation facile de choses comme TemporaryFolder.
  4. Je pense que nous ne pouvons pas modifier unilatéralement le modèle d'instanciation de Parameterized, car les tests actuels peuvent dépendre du comportement d'une instance par test. Comment pouvons-nous contourner cela?

une. Ajoutez une annotation ou un paramètre d'annotation pour activer le comportement différent.
b. Créez une sous-classe de Parameterized avec le comportement différent.
c. Une autre idée serait de créer une nouvelle instance de la classe de test pour chaque test, mais de transmettre à cette instance le même tableau d'objets de paramètres, qui pourrait être exploité par une règle de paramètre. Ce serait probablement plus gratifiant si les paramètres étaient regroupés dans un seul objet. Une idée potentiellement folle serait d'attacher la ParameterRule à la classe de paramètres elle-même...

Je pense que je préfère c à b, et b à a, mais ouvert à la discussion.

@dsaff

Nous devrions faire en sorte que cela se produise, et je suis heureux de travailler avec les parties intéressées.

Merci!

Nous ne pouvons pas modifier la signature des méthodes protégées. Mais extraire un methodBlock protégé (méthode FrameworkMethod, test d'objet) semble être une très bonne idée.

J'ai implémenté mes exigences ce matin, et j'ai fini par ne pas modifier cette signature de méthode (j'ai opté pour l'approche consistant à changer certaines méthodes internes de private -> protected).

Lors de l'écriture de l'interface ParameterRule, gardez à l'esprit que je pense que nous devons améliorer le fonctionnement de Rule et ClassRule. https://docs.google.com/document/d/1B6Z45BSGsY08rZqe2KUZTJ3RVsnUE1-HcXjl5MFm9ls/edit aide à expliquer où j'aimerais voir les choses avancer : ParameterRule pourrait particulièrement bénéficier de ce type d'approche de fabrique de règles, car cela permettrait une réutilisation facile de choses comme TemporaryFolder.

Je vais jeter un œil à cela et le garder à l'esprit.

Je pense que nous ne pouvons pas modifier unilatéralement le modèle d'instanciation de Parameterized, car les tests actuels peuvent dépendre du comportement d'une instance par test. Comment pouvons-nous contourner cela?

Mon implémentation est conditionnelle à l'existence d'une annotation @ParameterRule . S'il détecte qu'une méthode ou un champ est annoté avec cette annotation, il modifiera le modèle d'instanciation de Parameterized.

une. Ajoutez une annotation ou un paramètre d'annotation pour activer le comportement différent.

Voir au dessus.

b. Créez une sous-classe de Parameterized avec le comportement différent.

Cela pourrait très certainement être implémenté en tant que sous-classe et cela me conviendrait également. Mon processus de réflexion était de travailler avec la classe existante parce que cela semblait être l'intention de l'initiateur.

c. Une autre idée serait de créer une nouvelle instance de la classe de test pour chaque test, mais de transmettre à cette instance le même tableau d'objets de paramètres, qui pourrait être exploité par une règle de paramètre. Ce serait probablement plus gratifiant si les paramètres étaient regroupés dans un seul objet. Une idée potentiellement folle serait d'attacher la ParameterRule à la classe de paramètres elle-même...

Je ne suis pas sûr de suivre complètement, mais pourrais-je toujours satisfaire à l'exigence d'avoir une configuration commune qui est exécutée une fois par tableau de paramètres renvoyés par la méthode @Parameters ?

Préférez-vous que je soumette une demande d'extraction afin que nous ayons le code réel à discuter ?

@coreyjv , oui, je pense que si vous avez du code que vous êtes heureux de partager, c'est une excellente prochaine étape. Merci!

@dsaff

Ça a l'air bien, je vais essayer d'obtenir une demande de tirage ensemble dans les prochains jours.

@dsaff
@coreyjv

Y a-t-il déjà eu une solution à ce problème ? Nous avons des tests Junit qui utilisent l'option de paramètre pour spécifier différents navigateurs, tels que IE/Firefox/Chrome, et il lançait un nouveau navigateur pour chaque test, mais pour augmenter la vitesse d'exécution des tests, j'essayais de passer au démarrage et arrêter les navigateurs autour d'une classe de tests. Si j'utilise beforeClass et afterClass, il y a trop de temps entre la fin de l'un des paramètres et la fermeture du navigateur, de sorte que le pilote Web distant expire. J'aimerais utiliser cette approche AfterParameterRun, mais je vois beaucoup de discussions, et ce problème conduit à quelques demandes d'extraction, mais il ne semble pas que quelque chose ait jamais été fusionné dans main?
Merci,
Bradley

J'ai moi aussi un cas où j'aimerais voir une fonction 'AfterParameter'.

@coreyjv Cette fonctionnalité est-elle dans le pipeline parce que nous exécutons des cas de test paramétrés où nous avons besoin de telles annotations. @BeforeParam et @AfterParam sont requis.

@bileshg --

Par @dsaff, cette demande a été "mise sous cocon" il y a quelques années maintenant. Je m'en remets à lui s'il veut le refaire surface à nouveau. De plus, je ne sais pas si c'est quelque chose qui serait plus approprié pour JUnit 5 maintenant (je n'ai pas suivi les progrès là-bas).

@coreyjv D'accord. Merci d'avoir répondu. En fait, j'en avais besoin pour autre chose - Obtenir le nombre de cas de test échoués selon le paramètre. Jetez un oeil à cette question .

Je vois que "@BeforeParam/ @AfterParam for Parameterized runner #1435" a été fusionné et ajouté aux notes de version 4.13. Cela signifie-t-il qu'il y aura une version 4.13 ? Quand? J'ai un besoin urgent de cette fonctionnalité ! Je ne l'ai pas vu dans JUnit 5, donc je me demande quand je peux m'attendre à ce que @BeforeParam/ @AfteParam soit disponible.

@dstaraster actuellement la plupart de l'équipe JUnit se concentre sur la sortie de JUnit 5.0. J'espère que peu de temps après, nous pourrons commencer la version 4.13.

@kcooney Je suis également très intéressé par ces annotations @BeforeParam et @AfterParam (et malheureusement pas encore prêt à migrer mes milliers de tests vers JUnit5).
La version 4.13 est-elle toujours attendue ?

@raubel J'ai ouvert # 1496 pour discuter d'une version 4.13.

JUnit5 peut exécuter des tests de type JUnit4, vous n'avez donc pas besoin de migrer tous vos tests pour utiliser les fonctionnalités de JUnit5.

Cette page vous a été utile?
0 / 5 - 0 notes