Nunit: Attribut de dépendance de test

Créé le 3 nov. 2013  ·  59Commentaires  ·  Source: nunit/nunit

Salut,

J'ai une application Web avec des tests automatisés approfondis. J'ai des tests d'installation (supprimer les tables de base de données et réinstaller à partir de zéro), des tests de mise à niveau (de l'ancien au nouveau schéma), puis des tests Web normaux (obtenir cette page, cliquer dessus, etc.)

Je suis passé de NUnit à MbUnit car cela me permettait de spécifier des commandes de test via une dépendance (dépend d'une méthode de test ou d'un montage de test). Je suis revenu à NUnit et j'aimerais toujours cette fonctionnalité.

La solution de contournement actuelle (puisque je n'utilise que l'interface graphique NUnit) consiste à classer les noms de test par ordre alphabétique et à les exécuter appareil par appareil, avec l'installation/les premiers dans leur propre assemblage.

feature normal

Commentaire le plus utile

@aolszowka
Cela reste une fonctionnalité acceptée, du moins en ce qui concerne les étiquettes de problème. @nunit/framework-team Ai-je raison ?

Personne ne se l'est assigné, ce qui veut dire que personne n'y travaille. Intelligent de votre part de demander, néanmoins! Si vous souhaitez travailler dessus, un membre de l'équipe se l'attribuera probablement et "gardera un œil" sur vous, car GitHub ne nous laissera pas attribuer des problèmes à des non-membres.

J'en ai fait une fonctionnalité et lui ai donné sa priorité "normale" lorsque j'étais chef de projet. J'avais l'intention d'y travailler "un jour", mais je ne l'ai jamais fait et je ne le ferai jamais maintenant que je ne suis plus actif dans le projet. Je suis heureux de correspondre avec vous sur tous les problèmes que vous rencontrez si vous le prenez.

Mon conseil est de NE PAS faire ce que j'ai essayé de faire : rédiger une spécification complète, puis y travailler. Comme vous pouvez le lire dans les commentaires, nous avons continué à trouver des points de désaccord dans la spécification et personne ne l'a jamais déplacé vers la mise en œuvre. AFAIK (ou rappelez-vous), le travail préalable sur la manière dont les tests sont répartis a déjà été effectué. Je choisirais l'un des trois types de dépendance (voir mon commentaire il y a plus de deux ans) et un seul cas d'utilisation et je travaillerais dessus. Nous ne voudrons pas publier quelque chose tant que nous ne serons pas sûrs que l'API est correcte, vous devriez donc probablement compter sur une branche de fonctionnalité de longue durée qui doit être périodiquement rebasée ou fusionnée à partir de master. Gros boulot !

Tous les 59 commentaires

Ce bogue duplique et remplace https://bugs.launchpad.net/nunit-3.0/+bug/740539 qui a quelques discussions.

Bien que la dépendance et l'ordre ne soient pas identiques, ils sont liés dans le sens où l'ordre des tests est un moyen de modéliser la dépendance. Cependant, d'autres éléments peuvent avoir une incidence sur le classement, comme le niveau d'importance d'un test. En tout état de cause, les deux problèmes doivent être traités ensemble.

J'aime beaucoup le modèle MbUnit :

  • Dépendance à une autre suite de tests : annotez test (ou test fixture) avec [DependsOn(typeof(AnotherFixtureType))]
  • Dépendance à un autre test : annoter le test avec [DependsOn("TestInThisFixture")]

Que fait MbUnit si vous configurez une "dépendance" cyclique ?

Le dimanche 3 novembre 2013 à 12h25, ashes999 [email protected] a écrit :

J'aime beaucoup le modèle MbUnit :

  • Dépendance à une autre suite de tests : annotate test (ou test fixture)
    avec [Dépend de(typeof(AnotherFixtureType))]
  • Dépendance à un autre test : annoter le test avec
    [Dépend("TestDansCetAppareil")]


Répondez directement à cet e-mail ou consultez-le sur Gi tHubhttps://github.com/nunit/nunit-framework/issues/51#issuecomment -27653262
.

@CharliePoole si vous créez un cycle ou spécifiez une dépendance de méthode de test inexistante, MbUnit lève une exception d'exécution. Étant donné que dépendre d'une classe nécessite le type, ce serait similaire (selon un non-test) ou une erreur de compilation (ce type n'existe pas).

Une mise à jour sur ce problème ? J'ai choisi MbUnit à cause de la commande. Maintenant c'est en pause indéfinie, je dois chercher une alternative. Ce serait bien si NUnit pouvait prendre en charge cette fonctionnalité essentielle dans les tests d'intégration.

Désolé, pas encore de mise à jour, même si je viens également de MbUnit et que je l'utilise pour certains de nos tests d'intégration. Si vous souhaitez simplement ordonner les tests dans une classe de test, NUnit exécutera les tests par ordre alphabétique dans un appareil de test. Ceci n'est ni pris en charge ni documenté, mais cela fonctionne jusqu'à ce que nous ayons une alternative.

Je pensais que cela arriverait dans la v3?

Oui, mais ce n'est pas encore travaillé. Après la première alpha 3.0, nous allons
ajouter d'autres fonctionnalités.
Le 13 juin 2014 à 20h28, "fraser addison" [email protected] a écrit :

Je pensais que cela arriverait dans la v3?


Répondez directement à cet e-mail ou consultez-le sur GitHub
https://github.com/nunit/nunit-framework/issues/51#issuecomment -46044623
.

Pour la version 3.0, nous implémenterons un attribut de commande de test, plutôt qu'un attribut de dépendance de type MbUnit. Voir numéro 170

Voir mon commentaire au #170. La commande est très limitée et sujette à maintenance (sauf si vous utilisez des multiples de dix pour pouvoir insérer des tests au milieu sans tout réorganiser). MbUnit a des graphiques de dépendance arbitraires, dont j'ai (ou peut-être devrais-je dire "nous" puisque je ne suis pas le seul) vraiment besoin.

Dépendre d'un ordre alphabétique est une béquille, et assez faible étant donné que cela peut changer à tout moment.

Salut,

Le jeudi 7 août 2014 à 6 h 10, Ashiq A. [email protected] a écrit :

Voir mon commentaire au #170. La commande est très limitée et sujette à maintenance (sauf si vous utilisez des multiples de dix pour pouvoir insérer des tests au milieu sans tout réorganiser). MbUnit a des graphiques de dépendance arbitraires, dont j'ai (ou peut-être devrais-je dire "nous" puisque je ne suis pas le seul) vraiment besoin.

Oui. L'idée d'utiliser la commande est basée sur une hypothèse tacite : que
il ne sera pratiquement pas utilisé. Essayer de contrôler l'ordre d'exécution de
tous vos tests sont une très mauvaise idée. Cependant, dans de _rares_ cas, il peut
souhaitable de s'assurer d'abord de certains essais. Pour une utilisation aussi limitée, un
l'ordre des entiers est correct et la difficulté d'insérer de nouveaux éléments dans
l'ordre pourrait bien servir de découragement à inutilement
commander des tests.

Notez que ce problème concerne l'ordre des méthodes de test, et non
montages d'essai. Le problème #170 s'applique aux montages de test et non aux méthodes comme
écrite, car elle utilise un Type comme élément dépendant. Cela dit, le
les exemples du #170 semblent impliquer que l'ordre des méthodes est souhaité.

Fondamentalement, nous avons décidé que #170 nécessite trop de travail de conception pour
inclure dans la version 3.0 sans la retarder davantage. Nous avons élu -
dans ce cas et dans d'autres - pour limiter les nouvelles fonctionnalités en faveur d'un accès plus rapide
Libération. Attribuer #170 au jalon "Futur" ne le signifie pas
n'arrivera pas. Très probablement, nous l'aborderons dans une version intermédiaire.

L'utilisation d'un OrderAttribute était considérée comme un moyen de donner rapidement
"quelque chose" à ceux qui veulent contrôler l'ordre de la méthode de test
exécution. Nous avons estimé que nous pouvions l'intégrer rapidement. En fait, on peut avoir
eu tort. En y réfléchissant davantage, je vois que cela peut introduire
une capacité difficile à maintenir face au parallélisme
exécution des tests. En fait, une approche de dépendance générale peut être ce que nous
besoin. Pour le moment, je déplace les deux problèmes hors du jalon 3.0
jusqu'à ce que nous puissions les approfondir.

Dépendre d'un ordre alphabétique est une béquille, et assez faible étant donné que cela peut changer à tout moment.

En effet. Nous avons toujours conseillé aux gens de ne pas l'utiliser pour exactement cela
raison. En fait, il n'est pas garanti dans NUnit 3.0.

Charly

Je n'ai pas utilisé MbUnit depuis des années, mais j'aimerais ajouter à cette discussion si ma mémoire est bonne.

En supposant que [Test Z] dépend de [Test A]. Je lance ensuite [Test Z]. Il semble que NUnit évalue d'abord le résultat du [Test A]. S'il n'y a pas de résultat disponible, NUnit exécutera automatiquement [Test A] avant de tenter d'exécuter le [Test Z] demandé. NUnit n'exécutera [Test Z] que si [Test A] réussit. Sinon, [Test Z] sera marqué comme non concluant et indiquera sa dépendance vis-à-vis du [Test A] qui a échoué.

Ceux-ci pourraient fournir un aperçu:
https://code.google.com/p/mb-unit/source/browse/trunk/v3/src/MbUnit/MbUnit/Framework/DependsOnAssemblyAttribute.cs?spec=svn3066&r=1570

https://code.google.com/p/mb-unit/source/browse/trunk/v3/src/MbUnit/MbUnit/Framework/DependsOnAssemblyAttribute.cs?r=1570

@circa1741 : Nous travaillerons là-dessus dans le "futur", c'est-à-dire la version après la 3.0. La dépendance totale est vraiment une bête assez complexe à mettre en œuvre et nous prenons déjà beaucoup de choses en 3.0.

La commande de tests est un pansement si ce que vous voulez est une véritable dépendance, mais c'est assez facile à mettre en œuvre.

En faisant le tri (#170) en 3.0, nous courons un risque : certains utilisateurs le traiteront comme la réponse à leurs problèmes de dépendance et en viendront à en dépendre dans le mauvais contexte. Pourtant, cela semble mieux que de ne rien faire.

J'aimerais trouver le temps d'écrire un article sur les différents types de dépendance et de commande et sur la façon dont ils diffèrent dans leur utilisation et leur implémentation... peut-être... ;-)

Correction : après avoir écrit le commentaire précédent, j'ai remarqué que le #170 est également prévu pour 'future'.

Nous continuerons à discuter de la possibilité d'inclure une fonctionnalité de commande dans la version 3.0 par opposition à la version 3.2, mais pour le moment, elles ne sont pas prévues.

(Exemples tirés de http://blog.bits-in-motion.com/search?q=mbunit)

Lors de l'écriture de tests d'intégration, il est parfois utile d'enchaîner plusieurs tests qui capturent une séquence logique d'opérations.

MbUnit peut capturer ce chaînage soit avec des dépendances :
dependson
Permet également [DependsOn(typeof(ClassName.MethodName))]

Ou avec une commande explicite :
order

Merci pour l'exemple de code. Cela donne quelque chose à viser. Votre premier exemple est pertinent pour ce problème. Le second est exactement ce que nous prévoyons pour le #170.

J'ai une idée qui est plus une torsion pour la dépendance et la commande.

La discussion, jusqu'à présent, concernant la dépendance est "allez-y et exécutez le test H (et éventuellement 8 autres tests) uniquement si le test 8 réussit". En d'autres termes, il est inutile d'exécuter le test H car si le test 8 échoue, je sais que le test H échouera également.

Qu'en est-il d'une dépendance lorsqu'un test échoue ?

Scénario:
J'ai besoin d'un test de fumée qui couvre beaucoup de terrain. Donc, je prévois un montage de test qui est un test de bout en bout qui a une couverture de base de nombreuses fonctionnalités du SUT. Les tests sur ledit dispositif de test utiliseront la commande de test et ne sont "pas indépendants". L'ordre de test sera Test A puis Test B puis Test C, etc.

Maintenant, parce que les tests ne sont "pas indépendants", je sais que si le test C échoue, tous les tests suivants échoueront également. Par conséquent, j'ai besoin de plus de tests à exécuter afin d'obtenir une vue d'ensemble du test de fumée.

Je dois pouvoir configurer pour exécuter le test 1 si le test A échoue, le test 2 si le test B échoue, le test 3 si le test C échoue, etc.

Mon test 3 est conçu pour être indépendant du test B, donc si cela échoue, je comprends mieux pourquoi le test C a échoué plus tôt. Il s'avère que mes tests 4 (pour le test D), 5 (pour E), 5 (pour F), etc. sont tous réussis. Ensuite, je comprends maintenant que seule la fonctionnalité couverte par le test C est le problème.

Pourquoi ne pas exécuter les Tests 1, 2, 3, etc. à la place ? Eh bien, parce que ce sont des tests isolés et indépendants, je ne fais pas de tests d'intégration. Encore une fois, j'ai besoin d'un test de fumée qui couvre beaucoup de terrain.

Peut-être quelque chose comme :

  • [DependsOnPassing("Tester tel ou tel")]
  • [DependsOnFailing("Tester bla bla bla")]

Cela permettra un contrôle plus fin de la conception de mes tests d'automatisation.

Que diriez-vous plutôt de quelque chose comme ces attributs :

  • [DependsOnPassing("Tester tel ou tel")]
  • [RunOnFail("Tester bla bla bla")]

Veuillez noter à quel test ils sont attachés. Ces attributs doivent être utilisables à différents niveaux (et à n'importe quel niveau) : assemblage, montage de test, test.

[DependsOnPassing ("Test E")]
Essai F

  • Le test E sera automatiquement exécuté si son résultat est inconnu.
  • Ce n'est qu'alors que le test F sera déterminé s'il doit être exécuté ou non.

[RunOnFail("Test N")]
Je teste

  • Si le test I échoue, le test N sera automatiquement exécuté.

Essai N

  • Le test N peut être exécuté seul.
  • Mais il sera également exécuté automatiquement si le test I échoue.

Essai E

  • Le test E peut être exécuté seul.
  • Mais il sera également exécuté automatiquement si son résultat est inconnu car le test F dépend de la réussite de ce test en premier.

Copié à partir de # 1031, qui le duplique évidemment. Espérons que l'exemple aide et que les mots-clés dirigent les autres ici...

J'ai quelques cas où je voudrais marquer un test comme condition préalable à un autre test. Ce serait bien d'avoir un attribut indiquant les tests qui étaient des prérequis du test actuel.

Dans le cas où des routines dépendent les unes des autres, il est possible de savoir qu'un test donné va échouer car une sous-routine a échoué à son test. Si le test est long, il n'y a vraiment aucun intérêt à exécuter le test si la sous-routine est de toute façon interrompue.

Exemple artificiel :

public static class Statistics
{
    public static double Average(IEnumerable<double> values)
    {
        double sum = 0;
        double count = 0;
        foreach (var v in values)
        {
            sum += v;
            count++;
        }
        return sum / count;
    }

    public static double MeanVariance(IEnumerable<double> values)
    {
        var avg = Average(values);
        var variance = new List<double>();
        foreach (var v in values)
        {
            variance.Add(Math.Abs(avg - v));
        }
        avg = Average(variance);
        return avg;
    }
}

[TestFixture]
public class TestStatistics
{
    [Test]
    public void Average()
    {
        var list = new List<double> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
        var avg = Statistics.Average(list);
        Assert.AreEqual(4.5, avg);
    }

    [Test]
    //[Prerequisite("TestStatistics.Average")]
    public void MeanVariance()
    {
        //try { this.Average(); } catch { Assert.Ignore("Pre-requisite test 'Average' failed."); }
        var list = new List<double> { 1, 2, 3, 4, 5, 6, 7, 8, 9, 0 };
        var variance = Statistics.MeanVariance(list);
        Assert.AreEqual(0, variance);
    }
}

Étant donné l'exemple, si le test Average échoue, il est logique de ne pas s'embêter à tester MeanVariance .

Je concevrais ce fonctionnement en enchaînant les tests :

  • si MeanVariance est exécuté, Average est forcé de s'exécuter en premier.
  • Si Average a déjà été exécuté, les résultats peuvent être réutilisés.
  • Si Average échoue, MeanVariance est ignoré.

Existe-t-il des prévisions concernant la disponibilité de cette fonctionnalité ? Je n'ai pas trouvé cette information dans d'autres discussions, c'est peut-être une question en double.

C'est dans le jalon "Futur", c'est-à-dire après 3.2, qui est le dernier jalon réel que nous avons. Cependant, nous sommes sur le point de réaffecter les problèmes aux jalons, alors surveillez les changements.

Dans l'esprit d'étendre NUnit pour couvrir les besoins de test autres que les tests unitaires, je vais peser sur cette conversation. Jusqu'à présent, la conversation a été un pas dans la bonne direction, mais je pense qu'il manque un aspect clé.

Les tests unitaires sont intrinsèquement plats (c'est-à-dire la configuration, l'exécution d'un test, le démontage) et ne doivent dépendre d'aucun autre test ayant été exécuté. Les tests d'intégration ajoutent l'idée de tests ordonnés (ou de tests dépendants pour une définition de dépendant) dans lesquels, par exemple, la configuration se connecte au système, le test A crée un objet, le test B modifie l'objet créé par A, le test C supprime l'objet créé par A, et le démontage se déconnecte du système. Ce dernier exemple semble être ce dont la plupart des gens parlent dans ce fil.

Envisagez cependant de tester l'interface utilisateur d'un site Web, nous avons une page qui peut naviguer vers plusieurs autres pages, et certaines actions peuvent être effectuées sur cette page, ce qui peut affecter l'utilisation d'autres pages. Dans la structure de test unitaire, je dois accéder à la page A, créer l'objet A.1, accéder à la page B créer l'objet B.1. C'est un test, qui réimplémente le test de création de l'objet A.1 (à partir d'une page différente). Considérons maintenant que j'ai besoin d'un test qui modifie B.1 pour pointer vers A.1, je dois refaire tout ce que je viens de faire pour écrire ce test. Si nous modifions cet exemple pour l'adapter à l'analogie du test d'intégration, je dois faire un peu moins de travail pour la dernière étape, en ce sens que je peux compter sur le fait que B.1 est dans la même classe et peut donc faire une sorte de [DependsOn("Create_B1_Object")] attribut

Le point ici est que les tests d'interface utilisateur impliquent souvent une sorte d'arborescence pour votre suite de tests. Tous les tests enfants sous le nœud B exigent que B se termine avec succès, et B dépend de la réussite du nœud A, mais les voisins de B ne dépendent pas du tout de l'exécution de B. L'arborescence vous permet de tester toutes les fonctionnalités de la page A indépendamment de toute autre chose, mais comme la mise en page et les objets disponibles sur la page B reposent sur certaines fonctionnalités de la page A, cela peut dépendre du fait que toutes ces actions ont déjà été effectuées (au moyen de PageATests.CreateObject_A1 ayant été exécuté en tant que parent).

Dans l'arborescence, rien ne signifie que vous ne pouvez pas avoir de tests plats (unitaires) ou ordonnés (d'intégration), vous pouvez avoir le meilleur de tous, mais vous ajoutez la possibilité de faire des tests d'interface utilisateur.

Juste mon 0,02 $ pour ce que ça vaut

Exactement mes pensées. Vous voudriez une série de tests dont chaque test peut avoir une dépendance à l'autre. Les séries peuvent ou non être dépendantes les unes des autres. Plus ou moins ce qui est actuellement possible avec les tests ordonnés MSTest, autre que MSTest permet également la poursuite des tests même en cas d'échec.

Un exemple parfait sont les tests d'interface utilisateur qui sont souvent (toujours ?) sensibles à l'ordre et au contexte.

En dehors de MSTest, il n'existe aucun cadre de test activement développé qui permette de développer de tels types de tests.

@fgsahoward Je suis tout à fait d'accord avec vous, du moins à un niveau élevé - comme le montrera une lecture attentive des discussions passées.

Je dis "attention" parce que je suis en désaccord avec de nombreux détails spécifiques des propositions qui ont été faites. Comme vous pouvez le voir, il est maintenant répertorié comme une fonctionnalité de notre backlog. À mon sens, il faudra être prudent lors de sa mise en œuvre pour deux raisons principales :

  1. La fonctionnalité est souvent demandée par les personnes qui écrivent des tests unitaires.
  2. Certaines personnes (généralement les mêmes personnes) entendent quelque chose de différent par dépendance que vous.

Je suis généralement d'avis qu'un véritable séquençage des tests, en tant que série d'étapes, est essentiel pour de nombreux types de tests, y compris ceux que vous mentionnez. Je pense que nous devons rendre cela disponible d'une manière spécifique, qui minimise les chances que les gens les utilisent à d'autres fins. Cela signifie probablement qu'un attribut différent est utilisé pour annoter la classe ou l'espace de noms qui représente le test global ainsi qu'un autre attribut (différent) annotant les étapes de ce test.

IOW, je ne veux pas coller cette fonctionnalité au-dessus de TestFixture et Test.

Le deuxième problème devra probablement être traité par un attribut de dépendance quelconque, comprenant éventuellement une indication de la "force" relative de la dépendance. IOW, si ce que vous entendez par dépendance est "c'est une perte de temps d'exécuter B si A a échoué, car il échouera certainement", alors exécuter le test B ou non peut être au choix du framework.

En fait, ce que vous avez décrit est ce que j'appelle commander. L'ordonnancement peut être plus strict que la dépendance. En tant que développeur d'interface graphique (mon objectif principal depuis de nombreuses années), je ne veux pas spécifier de dépendances et faire en sorte que le cadre détermine l'ordre. Je veux spécifier explicitement la commande.

Une autre façon dont j'ai parlé de cela dans le passé est d'appeler ce dont vous parlez "dépendance stricte" et l'autre type "dépendance indirecte". Cela ne s'est pas avéré très clair pour la plupart des gens. Peut-être que lorsque nous produirons des implémentations de test, cela deviendra plus clair. :-)

@Sebazzz Merci pour le conseil sur MsTest, je peux voir si nous pouvons adapter cela à nos besoins d'une manière ou d'une autre jusqu'à ce que cette fonctionnalité soit développée.

@CharliePoole Je suis tout à fait d'accord, il doit y avoir une distinction très claire entre les types de tests que vous êtes sur le point de commencer à écrire. Je ne voudrais pas que toutes ces différentes fonctionnalités soient regroupées dans un seul attribut avec différentes configurations. Je suggérais plus ou moins que l'implémentation sous-jacente pourrait utiliser une structure arborescente pour tous les types de tests, les attributs déterminent simplement l'ordre et les dépendances.

Je pense qu'il est très clair que personne ne voudrait brouiller les lignes entre les différents styles de tests, afin de ne pas se retrouver avec un piratage des styles de test utilisés pour les tests unitaires. Merci pour vos notes, et j'attends avec impatience la solution que vous proposerez tous à l'avenir. :)

@oznetmaster Suite de la discussion du #170...

Nous avons eu de longues discussions sur les listes de nunit dans le passé sur ce que signifie la dépendance. Vos commentaires auraient très bien trouvé leur place ici et décriraient ce que j'ai souvent appelé la "dépendance stricte".

Le fait est que nous sommes motivés par les utilisateurs et les utilisateurs qui demandent une dépendance signifient souvent quelque chose de beaucoup moins précis que ce que vous décrivez. J'ai fait une analyse une fois et j'ai proposé trois définitions principales de la dépendance. Comme beaucoup de mes écrits passés, il s'est perdu en déplaçant le projet d'un endroit à un autre, mais si nous nous rapprochons de la mise en œuvre de quelque chose, je devrais essayer de le récupérer.

Fondamentalement - et peut-être trop simplement - j'ai découvert que les personnes disant que le test B dépend du test A signifiaient l'une des trois choses suivantes :

  1. Le test A établit les conditions préalables nécessaires pour que le test B s'exécute ou réussisse.
  2. Si le test A échoue, le test B échouera, il n'est donc pas nécessaire de l'exécuter. (différent de 1 car la corrélation n'est pas causale, mais due au fait que les deux tests nécessitent la même fonctionnalité pour fonctionner.)
  3. Si le test A échoue, c'est tout ce que nous devons savoir - le test B ne fournira aucune information utile.

Une différence clé avec les types 2 et 3 est que le framework peut choisir de les exécuter quand même si c'est plus pratique. Avec le type 1, le framework ne doit pas exécuter le Test B.

Les dépendances en cas d'échec plutôt qu'en cas de succès sont une belle extension.

Lorsque nous avons eu cette discussion, tous ceux qui avaient un point de vue pensaient que leur point de vue était "la" définition de la dépendance et tous les autres devaient utiliser un mot différent. :-) Je suis moins soucieux de connaître la bonne définition que de donner à chaque groupe ce qu'il demande.

Je suis entièrement d'accord avec tout cela.

Cependant, TestB s'exécute après que TestA n'ait établi qu'un ordre, exactement comme si TestA avait un ordre de 1 et TestB avait un ordre de 2. Il n'y a pas d'autre dépendance implicite dans les deux tests. TestB s'exécutera indépendamment de la réussite ou de l'échec de TestA, et il n'y a aucune hypothèse implicite que TestA "installe" TestB.. Ceci est différent de l'un des trois cas que vous avez énumérés. C'est pourquoi il s'agit vraiment d'une sémantique d'ordre, et non d'une dépendance. C'est exactement la même chose que d'utiliser des ordinaux pour la commande, mais beaucoup plus intuitif et plus facile à maintenir et s'auto-documente.

"TestB s'exécute après TestA" est ambigu. Après le démarrage de TestA ? finitions? réussit ?

Cependant, je comprends ce que vous dites. Il est possible d'utiliser une syntaxe de dépendance qui se traduit simplement par le type de classement que nous effectuons. Je suppose que cela pourrait être une quatrième signification de "dépend de" si nous voulions y aller.

Suggérez-vous que nous changions ce que nous faisons dans ce PR ? Ou faire autre chose à l'avenir ?

@oznetmaster À la fin, nous aurons probablement un maximum d'un "OrderAttribute" (ou similaire) et un "DependsOnAttribute". Nous devons soit choisir une signification claire pour chacun (si nous avons les deux), soit fournir une sorte de propriété permettant à l'utilisateur de choisir parmi plusieurs significations. Accepteriez-vous?

Cela me semble raisonnable. Si nous optons pour un arbre de dépendance pour chacun d'eux, alors un seul attribut fonctionnerait, avec des conditions différentes pour ce que signifie sa dépendance.

Il semble que l'ordre ordinal soit également ambigu. Qu'est-ce que la commande 1, 2, 3, signifie réellement. Commencent-ils dans cet ordre ? Attendent-ils que les premiers soient terminés avant de commencer ?

Je pense que ce PR pourrait tout faire. L'ordre et la dépendance nécessitent la construction d'un arbre de dépendance logique. C'est la première étape.

Ce qui est fait avec cet arbre pourrait être deux PR, ou celui-ci seul. Je sais que vous aimez les petits PR, mais je n'ai pas une bonne idée de l'importance de tout faire dans un seul PR.

Les problèmes de dépendance croisée TestFixture (ou dépendance TestFixture) entrent également en jeu, tout comme les dépendances d'assemblage de test croisé. Je ne suggère pas que nous les fassions tous, mais nous devrions au moins les considérer. Ceci s'applique également aux commandes simples.

Sauf que ce n'est pas un PR. Pas seulement une chicane sémantique : aucun travail n'a été fait dessus et il n'est même pas programmé ou assigné. OTOH, l'autre est quelque chose pour lequel nous avons du code en ce moment.

Je pense que c'est un gros problème à moins que certains travaux préliminaires ne soient d'abord effectués séparément. Nous devons disposer d'un moyen arbitraire pour spécifier les dépendances entre les éléments de travail et les planifier en conséquence. Ce n'est pas comme ça que nous procédons maintenant. Nous n'avons aucune notion d'éléments attendant que d'autres éléments soient terminés. Le numéro 1096 pourrait mener à cela. Il est actuellement prévu au jalon 3.4.

Bien sûr, nous pourrions créer une sorte de dépendance ad hoc sans cela, mais nous finirions probablement par la refaire à la fin. IMO, un graphique de dépendance généralisé entre les éléments de travail est ce que nous voulons vraiment avoir. Ensuite, il devient assez facile d'implémenter différentes couches utilisateur par-dessus.

BTW, on a l'impression que nous entrons souvent dans de larges discussions comme celle-ci au moment où nous essayons de ramener à la maison un objectif de sortie. J'aimerais pouvoir le faire au début d'une itération !

Je suis très intéressé à travailler sur cet article. Je commencerais par proposer une "syntaxe" pour spécifier la dépendance. La commande de test (non dépendante) en ferait partie. Je voudrais également le faire fonctionner avec la même syntaxe sur TestFixture ainsi que sur Test.

Comme on l'a noté, cela existe depuis longtemps. Est-il encore trop tôt pour s'y mettre réellement ?

Non, pas trop tôt pour comprendre la syntaxe de toute façon. Je vous suggère de créer une spécification sur le dev wiki. J'ai quelques idées auxquelles j'aimerais contribuer... comme très brièvement décrit dans l'un des commentaires ci-dessus. Je pense que la distinction clé est entre les dépendances "dures", que NUnit doit suivre, et les "plus douces", qui ne sont essentiellement que des indices du framework.

J'ai également une assez bonne idée de la façon de l'implémenter, y compris de l'utiliser pour piloter les phases de configuration et de démontage décrites dans le numéro 1096.

Cela reviendrait à changer le test de "répartition" de son mécanisme "push" actuel en un mécanisme "pull".

"Créer une spécification sur le wiki de développement" ? Aucune idée de comment faire ça :(

Vous ne savez pas pourquoi vous faites référence à la répartition des tests comme un mécanisme "push". Les travailleurs extraient les éléments des files d'attente lorsqu'ils sont prêts à les exécuter. Je prévois de travailler sur # 1096 et j'accueille toutes les suggestions.

Peut-on modifier un wiki ? Je vais créer une page vide au bon endroit si vous le souhaitez. Sinon, cela peut être du texte ici, bien sûr, mais le faire sur le wiki nous donnerait une longueur d'avance pour le documenter plus tard.

CompositeWorkItem parcourt essentiellement ses enfants et "pousse" chacun d'eux pour qu'il soit exécuté.

Je vois une implémentation de dépendance qui crée une "file d'attente" linéaire de chaque élément de travail dans le test, un peu comme une file d'attente de planificateur dans un système d'exploitation, qui spécifie les conditions dans lesquelles chaque élément peut être autorisé à s'exécuter. Le répartiteur supprime l'élément de travail "exécutable" supérieur de la file d'attente à exécuter (s'il est parallèle, chaque "thread" de travail supprimerait l'élément de travail exécutable suivant qui peut être parallélisé). Lorsqu'un élément de travail est terminé, il bascule alors la "fonctionnalité" des autres éléments de la file d'attente, peut-être même en supprimant ceux qui ne seront plus exécutés en raison de leur dépendance.

Il peut même être possible d'exprimer la parallélisabilité comme une condition de dépendance.

Je vois # 1096 comme faisant partie intégrante du même processus. Une fois que plusieurs éléments de travail sont créés, chacun d'entre eux se verra attribuer une propriété de dépendance qui contrôlera le moment où ils seront exécutés.

Je n'ai aucune idée si je peux éditer un wiki. Jamais essayé, et je ne sais pas comment faire. Pouvez-vous me donner un "coup de pouce" de départ ? :)

@oznetmaster , éditer le wiki est assez facile,

  1. Choisissez une page à partir de laquelle vous souhaitez ajouter un lien vers votre nouvelle page wiki, probablement la page Spécifications ,
  2. Modifier la page en cliquant sur le bouton
  3. Ajoutez un lien en entourant le texte de doubles crochets comme [[My NUnit Spec]]
  4. Enregistrer la page
  5. En voyant le nouveau lien, il est rouge indiquant que la page n'existe pas
  6. Cliquez sur le lien rouge, il vous amènera à une nouvelle page de création
  7. Modifiez la page comme vous le feriez avec un problème en utilisant GitHub markdown et enregistrez

@oznetmaster Ce que vous décrivez est à peu près la façon dont le répartiteur parallèle fonctionne déjà. Les éléments sont affectés à des files d'attente individuelles en fonction de leurs caractéristiques. Actuellement, il prend en compte la parallélisabilité et les exigences d'appartement. Tous les éléments, une fois mis en file d'attente, sont prêts à être exécutés.

Il a toujours été prévu que des files d'attente de dépendance seraient ajoutées comme étape supplémentaire. Je prévois d'utiliser #1096 comme "excuse" pour implémenter cette infrastructure. Une fois implémenté, il peut ensuite être davantage exposé aux utilisateurs, comme indiqué au #51. Je vais également préparer une spécification pour le mécanisme de planification sous-jacent (répartiteur) et j'aimerais avoir vos commentaires à ce sujet.

@oznetmaster j'ai créé une page vide pour vous : https://github.com/nunit/dev/wiki/Test-Dependency-Attribute

Sommes-nous engagés à appeler l'attribut DependsOnAttribute ? Que diriez-vous de quelque chose de plus général comme "DependenciesAttribute" ?

C'est chiant, je sais :(

Vous devriez l'écrire comme vous pensez qu'il devrait être. Ensuite, nous nous battrons tous à ce sujet. :-)

Donc j'ai :)

Suggestion : ajouter une section qui explique la motivation pour chaque type de dépendance. Par exemple, quand un utilisateur voudrait-il généralement utiliser AfterAny, etc.

En tant que développeur, il est toujours tentant d'ajouter des éléments pour "l'exhaustivité". Essayer d'imaginer un utilisateur ayant besoin de chaque fonctionnalité est un frein utile à cette tendance. Malheureusement, les utilisateurs ne nous disent généralement que quand quelque chose manque, pas quand quelque chose ne leur est pas utile.

Pour ce que ça vaut, ma contribution :

Je préfère ne pas définir une dépendance _par méthode de test_, qui devient plutôt fastidieuse (et difficile à maintenir) si vous avez plus que quelques tests. Au lieu de cela, je veux établir un ordre entre les appareils de test. Cela vient du cas suivant que nous avons actuellement : Nous utilisons actuellement MSTest pour les tests commandés. Sauf qu'il s'agit de MSTest, cela fonctionne très bien, car avec l'ordre des tests, je peux exprimer deux choses à propos d'un test : certains tests _peuvent ne pas s'exécuter avant_ un autre test. D'autres tests ont une _dépendance_ sur un autre test et ne peuvent _être exécutés qu'après_ que les autres tests ont été exécutés.

Disons que le test d'intégration :

  • Utilise une base de données de test avec plusieurs comptes d'utilisateurs
  • Les premiers tests exécutent certains tests à l'aide des données de test et créent également des données de test elles-mêmes à utiliser dans un test ultérieur. Notez que nous avons une relation de _dépendance_ ici. Certains tests peuvent ne pas s'exécuter si des tests antérieurs échouent.
  • Ensuite, des tests d'automatisation du navigateur se produisent. Ils doivent être exécutés le plus tard possible, car ils prennent beaucoup de temps et nous voulons d'abord avoir les commentaires des tests précédents (plus rapides).
  • Enfin, une logique est testée qui supprime un compte d'utilisateur entier. Notez que nous avons ici une relation _ne doit pas s'exécuter avant_ : si ce test devait être effectué avant les autres tests, les autres tests échoueraient.

Avec MSTest, je peux bien exprimer ce cas : chaque "test ordonné" dans MSTest peut contenir lui-même des tests ordonnés. De plus, les tests ordonnés peuvent avoir un indicateur défini pour abandonner si l'un des tests échoue.

              /      |         \
   DomainTests  BrowserTests  DestructiveTests
    /   |  \       /  |   \      |   \ 
   A    B   C     D   E    F     G    H 

Par exemple, MyPrimaryOrderedTest a l'échec 'abandon en cas d'échec' défini sur faux. Rien n'empêche BrowserTests de s'exécuter si DomainTests échoue. Cependant, DomainTests lui-même a le drapeau défini sur vrai, donc le test C n'est pas exécuté si A ou B échouent. Notez que A jusqu'à H peut être soit une définition de test ordonnée elle-même, soit un montage de test.

Pour être concret, si je pensais à une interface comme celle-ci pour exprimer la commande des appareils de test :

interface ITestCollection {
    IEnumerable<Type> GetFixtureTypes();
    bool ContinueOnFailure { get; }
}

C'est beaucoup plus maintenable (et évident) car avoir des attributs de dépendance sur chaque appareil et s'adapte bien mieux à mesure que le nombre d'appareils augmente.

Remarque pour les tests de commande _within_ fixtures, j'utiliserais simplement les OrderAttribute existants pour cela. Je pense que les méthodes de test ne devraient pas avoir de dépendances de test inter-appareils, car cela rend la structure de test trop complexe et impossible à maintenir.

Pour la commande de test entre les appareils, j'ai mis en place un prototype et j'ai constaté que l'expression des dépendances entre les appareils en utilisant des attributs devient désordonnée, même avec seulement quelques tests. Veuillez également noter que le prototype ne permettrait pas de commander au-delà de l'espace de noms dans lequel l'appareil est défini car chaque appareil fait partie d'un test parent avec le nom de l'espace de noms. J'aurais besoin d'implémenter mon propre ITestAssemblyBuilder pour contourner cela, mais NUnit est codé en dur pour utiliser le DefaultTestAssemblyBuilder actuel.

Mise à jour de mon côté : entre-temps, j'ai réussi à implémenter la commande de test sans avoir besoin de bifurquer NUnit. C'est "assez bon" pour moi, donc je l'utilise maintenant. C'est déjà beaucoup mieux que l'état fragile de nombreux tests commandés par MSTest.

Par curiosité, y a-t-il une chance que la fonctionnalité de dépendance soit prévue pour la prochaine version ?

Aucun projet pour le moment. Pour votre information, vous pouvez le voir ici sur GitHub en raison du fait qu'il n'est attribué à personne et qu'aucun jalon n'est spécifié.

Pour les éléments prioritaires normaux, comme celui-ci, nous ne les pré-planifions généralement pas pour une version particulière. Nous réservons cela pour les articles élevés et critiques. Celui-ci n'entrera dans un plan de publication que lorsque quelqu'un décidera de le faire, l'auto-assignera et l'amènera à un point où il sera prêt à être fusionné.

En fait, bien qu'il n'en dépende pas réellement, ce problème nécessite un tas de choses du # 164 pour être efficacement traité. Je travaille là-dessus et j'espère le pousser dans la prochaine version.

Pertinent : https://stackoverflow.com/questions/44112739/nunit-using-a-separate-test-as-a-setup-for-a-subsequent-test

J'ai été référé ici à partir de là. Je suis fermement convaincu que tout défaut ne devrait jamais faire échouer qu'un seul test unitaire, faire échouer tout un tas d'autres parce qu'ils dépendent de ce défaut ne pas être là est .. au mieux indésirable, et plus qu'un peu de temps Consommer à essayer de retrouver lequel des tests défaillants est le plus pertinent.

Edit : En regardant simplement mon code existant, j'ai une méthode " Prerequisite (Action action)" dans plusieurs de mes montages de test qui encapsule l'appel à l'action dans un try/catch AssertionException/throw Non concluant, mais il fait aussi un peu de nettoyage des trucs comme 'substitute.ClearReceivedCalls' (de NSubtitute) et vide une liste remplie par 'testObj.PropertyChanged += (sender,e) => receiveEvents.Add(e.PropertyName)'; sinon les actions passées contaminent potentiellement les appels à 'substitute.Received..'

Il peut être nécessaire d'inclure également une sorte de méthode 'Cleanup' dans l'attribut de dépendance pour prendre en charge des choses comme celle-ci.

@ Flynn1179 - Je suis d'accord avec vous en ce qui concerne les tests _unitaire_. Cependant, NUnit est également un excellent outil pour d'autres types de tests. Par exemple, nous l'utilisons pour tester le firmware embarqué et il nous manque vraiment cette fonctionnalité...

@ Flynn1179 Entièrement d'accord avec vous. Il existe des techniques pour empêcher les fausses pannes telles que celles que vous décrivez qui ne "dépendent" pas d'une fonctionnalité de dépendance de test. En général, utilisez une hypothèse pour tester les choses qui sont réellement testées dans un test différent et qui sont nécessaires pour que votre test ait un sens.

C'était un objectif de NUnit 3 d'étendre NUnit pour une utilisation efficace avec des tests non unitaires. Nous ne l'avons vraiment pas encore fait - cela peut attendre une autre version majeure. OTOH, les utilisateurs continuent de l'utiliser à ces autres fins et essaient de trouver des moyens intelligents de gérer les limitations. Ici et là, nous avons ajouté de petites fonctionnalités et améliorations pour les aider, mais il s'agit toujours principalement d'un framework de tests unitaires.

Personnellement, je doute que je veuille moi-même utiliser la dépendance dans le cadre de tests de haut niveau. Au lieu de cela, je préférerais avoir un autre type d'appareil qui exécute une série d'étapes dans un certain ordre, signalant le succès ou l'échec de chaque étape et continuant ou s'arrêtant en fonction d'une propriété de l'étape. Cela, cependant, est une toute autre question.

@espenalb Je serais intéressant de savoir ce que vous pensez être nécessaire, en particulier pour tester le micrologiciel intégré.

Nous sommes en fait très heureux de ce que propose NUnit.

Nous utilisons une combinaison d'attributs FixtureSetup/Setup/test pour configurer l'appareil (y compris le micrologiciel clignotant)

Ensuite, nous utilisons différentes interfaces (port série, jtag, ethernet) pour interagir avec les appareils, généralement nous envoyons des commandes, puis observons les résultats. Les résultats peuvent être une réponse de commande, ou dans des tests avancés, nous utilisons un équipement matériel dédié pour mesurer le comportement de l'appareil.

Les macros d'assertion NUnit et FluentAssertions sont ensuite utilisées pour vérifier que tout va bien.
Par définition, ce sont tous des tests d'intégration - et par nature beaucoup plus lents qu'un test unitaire régulier. La question de la dépendance du test est donc cruellement manquée - il ne sert à rien de vérifier par exemple les performances du capteur si la commande d'activation du capteur a été rejetée. La possibilité de reprendre un test là où un autre est terminé est donc très précieuse.

Avec l'attribut de dépendance de test, nous aurions _un_ test défaillant, puis _n_ tests ignorés/ignorés où les tests ignorés pourraient indiquer clairement qu'ils n'ont pas été exécutés car les autres tests ont échoué...

Une autre différence par rapport aux tests unitaires réguliers est l'utilisation intensive du rédacteur de journal. Il y a un problème concernant le multithreading et le journal pour lequel je créerai un problème séparé s'il n'existe pas déjà.

Conclusion de notre part - nous sommes _très_ satisfaits de NUnit en tant que harnais de test pour les tests d'intégration. Il nous offre un excellent support pour de nombreux scénarios avancés en utilisant C # pour interagir avec Device Under Test et d'autres équipements de laboratoire.

Avec ReportUnit, nous obtenons ensuite de beaux rapports html et nous obtenons également l'intégration de Jenkins en utilisant la sortie de test rev2 nunit.

nous obtenons également l'intégration de Jenkins en utilisant la sortie de test rev2 nunit.

@espenalb - Complète à part, mais le plugin Jenkins a récemment été mis à jour pour lire la sortie NUnit 3. 🙂

Quelqu'un peut-il donner une petite mise à jour sur l'état de cette fonctionnalité ? Est-ce prévu ?
Dans mon département, nous faisons des tests de très longue durée, qui dépendent logiquement beaucoup les uns des autres.
Une sorte de "Test-Dependency" serait vraiment intéressant et nous aiderait...

J'ai entendu dire que vous prévoyiez en général "d'ouvrir" NUnit pour les tests de "test non unitaire" également (ce qui est fondamentalement le cas pour nous...). Je pense que cet attribut serait un pas vers cela :-)

Cette fonctionnalité est encore en phase de conception, donc à part l'utilisation de bibliothèques externes, il n'y a pas de support intégré actuellement.

Je suis désolé de remonter un vieux fil, mais au cours de notre travail sur NUnit avec un ami, nous sommes tombés sur un cas où si nous avions une telle fonctionnalité, nous pourrions commencer à créer des tests d'intégration (je réalise que NUnit est un cadre de test unitaire, mais il semble que nous pourrions obtenir ce que nous voulons si nous avions la dépendance de test).

Voici d'abord un lien mis à jour vers la spécification proposée (le lien de CharliePoole ici https://github.com/nunit/nunit/issues/51#issuecomment-188056417 était mort): https://github.com/nunit/docs/ wiki/Test-Dependency-Attribute-Spec

Maintenant, pour un cas d'utilisation ; considérez le programme de jouets suivant et les tests associés

namespace ExampleProgram
{
    using System.Collections;
    using NUnit.Framework;

    public static class ExampleClass
    {
        public static int Add(int a, int b)
        {
            return a - b;
        }

        public static int Increment(int a)
        {
            return Add(a, 1);
        }
    }

    public class ExampleClassTests
    {
        [TestCaseSource(typeof(AddTestCases))]
        public void Add_Tests(int a, int b, int expected)
        {
            int actual = ExampleClass.Add(a, b);
            Assert.That(actual, Is.EqualTo(expected));
        }

        [TestCaseSource(typeof(IncrementTestCases))]
        public void Increment_Tests(int a, int expected)
        {
            int actual = ExampleClass.Increment(a);
            Assert.That(actual, Is.EqualTo(expected));
        }
    }

    internal class IncrementTestCases : IEnumerable
    {
        public IEnumerator GetEnumerator()
        {
            yield return new TestCaseData(0, 1);
            yield return new TestCaseData(-1, 0);
            yield return new TestCaseData(1, 2);
        }
    }

    internal class AddTestCases : IEnumerable
    {
        public IEnumerator GetEnumerator()
        {
            yield return new TestCaseData(0, 0, 0);
            yield return new TestCaseData(0, 2, 2);
            yield return new TestCaseData(2, 0, 2);
            yield return new TestCaseData(1, 1, 2);
        }
    }
}

En tant qu'implémenteur, je sais que si des tests unitaires autour Add(int,int) échouent, il est absolument inutile d'exécuter tous les tests supplémentaires autour Increment(int) autres que le bruit. Cependant, il ne semble pas y avoir de moyen (à part Test Dependency) de le spécifier à NUnit (du moins dans mes recherches).

En faisant beaucoup de recherches en ligne, il semble que d'autres aient travaillé autour de cela en utilisant une combinaison de facteurs (dont aucun n'est explicitement clair que Increment(int) dépend de Add(int,int) ) tels que :

  • Utilisation des catégories
  • Utilisation d'une convention de dénomination pour contrôler l'ordre des tests

Aucun de ceux-ci ne semble bien évoluer, ni même fonctionner d'ailleurs lorsque vous utilisez d'autres fonctionnalités telles que Parallel et tous nécessitent un "post-traitement" externe une fois l'exécution de NUnit terminée.

Est-ce la meilleure voie à suivre (si nous devions utiliser NUnit pur) ? Cette fonctionnalité est-elle toujours en cours d'élaboration ? (En d'autres termes, si un PR était soumis, cela bloquerait-il quelqu'un d'autre travaillant sur quelque chose de lié ?)

Il y a beaucoup de bonnes discussions dans ce fil sur les dépendances cycliques et d'autres problèmes potentiels avec cette fonctionnalité, ce n'est évidemment pas facile à résoudre, sinon quelqu'un l'aurait déjà fait. Je suis sûr que l'ajout de Parallel et TestCaseSource dans le mélange augmente également la complexité. J'ai l'intention de creuser davantage à un moment donné, mais avant de le faire, je voulais m'assurer qu'il ne s'agissait pas d'un problème résolu ou de plans en cours.

@aolszowka
Cela reste une fonctionnalité acceptée, du moins en ce qui concerne les étiquettes de problème. @nunit/framework-team Ai-je raison ?

Personne ne se l'est assigné, ce qui veut dire que personne n'y travaille. Intelligent de votre part de demander, néanmoins! Si vous souhaitez travailler dessus, un membre de l'équipe se l'attribuera probablement et "gardera un œil" sur vous, car GitHub ne nous laissera pas attribuer des problèmes à des non-membres.

J'en ai fait une fonctionnalité et lui ai donné sa priorité "normale" lorsque j'étais chef de projet. J'avais l'intention d'y travailler "un jour", mais je ne l'ai jamais fait et je ne le ferai jamais maintenant que je ne suis plus actif dans le projet. Je suis heureux de correspondre avec vous sur tous les problèmes que vous rencontrez si vous le prenez.

Mon conseil est de NE PAS faire ce que j'ai essayé de faire : rédiger une spécification complète, puis y travailler. Comme vous pouvez le lire dans les commentaires, nous avons continué à trouver des points de désaccord dans la spécification et personne ne l'a jamais déplacé vers la mise en œuvre. AFAIK (ou rappelez-vous), le travail préalable sur la manière dont les tests sont répartis a déjà été effectué. Je choisirais l'un des trois types de dépendance (voir mon commentaire il y a plus de deux ans) et un seul cas d'utilisation et je travaillerais dessus. Nous ne voudrons pas publier quelque chose tant que nous ne serons pas sûrs que l'API est correcte, vous devriez donc probablement compter sur une branche de fonctionnalité de longue durée qui doit être périodiquement rebasée ou fusionnée à partir de master. Gros boulot !

Cela reste une fonctionnalité acceptée, du moins en ce qui concerne les étiquettes de problème. @nunit/framework-team Ai-je raison ?

Oui - en ce qui me concerne !

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