J'ai une sorte de données de test et je souhaite créer un test unitaire pour chaque élément. Ma première idée a été de le faire comme ceci:
import unittest
l = [["foo", "a", "a",], ["bar", "a", "b"], ["lee", "b", "b"]]
class TestSequence(unittest.TestCase):
def testsample(self):
for name, a,b in l:
print "test", name
self.assertEqual(a,b)
if __name__ == '__main__':
unittest.main()
L'inconvénient est qu'il gère toutes les données en un seul test. Je voudrais générer un test pour chaque élément à la volée. Aucune suggestion?
python
unit-testing
parameterized-unit-test
Peter Hoffmann
la source
la source
Réponses:
C'est ce qu'on appelle la "paramétrisation".
Il existe plusieurs outils qui soutiennent cette approche. Par exemple:
Le code résultant ressemble à ceci:
Qui va générer les tests:
Pour des raisons historiques, je laisserai la réponse originale vers 2008):
J'utilise quelque chose comme ça:
la source
.__name__ =
pour activer les.exact_method
testsif __name__ == '__main__'
conditionnel? Il devrait sûrement aller au-delà de cela pour s'exécuter au moment de l'importation (en se souvenant que les modules python ne sont importés qu'une seule fois même s'ils sont importés de plusieurs endroits différents)Utiliser unittest (depuis 3.4)
Depuis Python 3.4, le
unittest
package de bibliothèque standard a lesubTest
gestionnaire de contexte.Voir la documentation:
Exemple:
Vous pouvez également spécifier un message personnalisé et des valeurs de paramètres pour
subTest()
:Utiliser le nez
Le cadre de test de nez prend en charge cela .
Exemple (le code ci-dessous est l'intégralité du contenu du fichier contenant le test):
La sortie de la commande nosetests:
la source
Cela peut être résolu avec élégance à l'aide de métaclasses:
la source
__new__
méthode dans la métaclasse est appelée lorsque la classe elle-même est définie, pas lorsque la première instance est créée. J'imagine que cette méthode de création dynamique de méthodes de test est plus compatible avec l'introspection utilisée parunittest
pour déterminer le nombre de tests dans une classe (c'est-à-dire qu'elle peut compiler la liste des tests avant de créer une instance de cette classe).class TestSequence(unittest.TestCase, metaclass=TestSequenceMeta):[...]
dct
place dedict
? L'utilisation de mots clés comme noms de variables est source de confusion et est source d'erreurs.Depuis Python 3.4, des sous-tests ont été introduits pour unittest à cet effet. Voir la documentation pour plus de détails. TestCase.subTest est un gestionnaire de contexte qui permet d'isoler des assertions dans un test afin qu'un échec soit signalé avec des informations sur les paramètres mais n'arrête pas l'exécution du test. Voici l'exemple de la documentation:
La sortie d'un essai serait:
Cela fait également partie de unittest2 , il est donc disponible pour les versions antérieures de Python.
la source
setUp()
ettearDown()
ne sont pas exécutés entre les sous-tests.)self.setUp()
peut en théorie être appelé manuellement depuis le sous-test. Quant àtearDown
, le faire appeler automatiquement à la fin pourrait suffire.load_tests est un mécanisme peu connu introduit en 2.7 pour créer dynamiquement un TestSuite. Avec lui, vous pouvez facilement créer des tests paramétrés.
Par exemple:
Ce code exécutera tous les TestCases dans la TestSuite retournée par load_tests. Aucun autre test n'est exécuté automatiquement par le mécanisme de découverte.
Alternativement, vous pouvez également utiliser l'héritage comme indiqué dans ce ticket: http://bugs.python.org/msg151444
la source
Cela peut être fait en utilisant pytest . Écrivez simplement le fichier
test_me.py
avec le contenu:Et lancez votre test avec la commande
py.test --tb=short test_me.py
. La sortie ressemblera alors à:C'est simple !. Aussi pytest a plus de fonctionnalités comme
fixtures
,mark
,assert
, etc ...la source
py.test
unittest
py.test. J'avais l'habitude d'avoir desTestCase
classes de base qui pouvaient créer dynamiquement des enfants avec différents arguments qu'ils stockaient comme variables de classe ... ce qui était un peu lourd.py.test
est yield_fixtures . Ce qui peut faire la configuration , renvoyer des données utiles dans le test et après la fin du test, faire le démontage . Les luminaires peuvent également être paramétrés .Utilisez la bibliothèque ddt . Il ajoute des décorateurs simples pour les méthodes de test:
Cette bibliothèque peut être installée avec
pip
. Il ne nécessite pasnose
et fonctionne parfaitement avec leunittest
module de bibliothèque standard .la source
Vous auriez avantage à essayer la bibliothèque TestScenarios .
la source
Il y a aussi l'hypothèse qui ajoute des tests basés sur des propriétés ou des fuzz: https://pypi.python.org/pypi/hypothesis
Il s'agit d'une méthode de test très puissante.
la source
@given()
macro dans la classe la plus unitaire.Vous pouvez utiliser le plugin nose-ittr (
pip install nose-ittr
).Il est très facile à intégrer aux tests existants, des modifications minimales (le cas échéant) sont requises. Il prend également en charge le plugin de traitement multi- nez .
Non pas que vous puissiez également avoir une
setup
fonction de personnalisation par test.Il est également possible de passer des
nosetest
paramètres comme avec leur plug-in intégréattrib
, de cette façon, vous ne pouvez exécuter qu'un test spécifique avec un paramètre spécifique:la source
J'utilise des métaclasses et des décorateurs pour générer des tests. Vous pouvez vérifier mon implémentation python_wrap_cases . Cette bibliothèque ne nécessite aucun framework de test.
Votre exemple:
Sortie console:
Vous pouvez également utiliser des générateurs . Par exemple, ce code génère toutes les combinaisons possibles de tests avec des arguments
a__list
etb__list
Sortie console:
la source
Je suis tombé sur ParamUnittest l'autre jour en regardant le code source du radon ( exemple d'utilisation sur le dépôt github ). Il devrait fonctionner avec d'autres frameworks qui étendent TestCase (comme Nose).
Voici un exemple:
la source
RÉSULTAT:
la source
def add_test_methods
fonction. Devrais-def _add_test_methods
je êtreUtilisez simplement des métaclasses, comme on le voit ici;
Production:
la source
Vous pouvez utiliser
TestSuite
desTestCase
classes personnalisées .la source
__init__
fonctionner.J'ai trouvé que cela fonctionne bien pour mes besoins, surtout si j'ai besoin de générer des tests qui font des processus légèrement différents sur une collection de données.
La
TestGenerator
classe peut être utilisée pour générer différents ensembles de cas de test commeTestCluster
.TestCluster
peut être considéré comme une implémentation de l'TestGenerator
interface.la source
Cette solution fonctionne avec
unittest
etnose
pour Python 2 et Python 3:la source
J'avais eu des problèmes avec un style très particulier de tests paramétrés. Tous nos tests Selenium peuvent s'exécuter localement, mais ils devraient également pouvoir être exécutés à distance sur plusieurs plates-formes sur SauceLabs. Fondamentalement, je voulais prendre une grande quantité de cas de test déjà écrits et les paramétrer avec le moins de changements de code possible. De plus, j'avais besoin de pouvoir passer les paramètres dans la méthode setUp, chose pour laquelle je n'ai vu aucune solution ailleurs.
Voici ce que j'ai trouvé:
Avec cela, tout ce que j'avais à faire était d'ajouter un simple décorateur @sauce_labs () à chaque ancien TestCase ordinaire, et maintenant lors de leur exécution, ils sont emballés et réécrits, de sorte que toutes les méthodes de test sont paramétrées et renommées. LoginTests.test_login (self) s'exécute en tant que LoginTests.test_login_internet_explorer_10.0 (self), LoginTests.test_login_internet_explorer_11.0 (self) et LoginTests.test_login_firefox_43.0 (self), et chacun a le paramètre self.platform pour décider quel navigateur / contre laquelle fonctionner, même dans LoginTests.setUp, ce qui est crucial pour ma tâche puisque c'est là que la connexion à SauceLabs est initialisée.
Quoi qu'il en soit, j'espère que cela pourrait être utile à quelqu'un qui cherche à faire un paramétrage "global" similaire de leurs tests!
la source
Les réponses basées sur les métaclasses fonctionnent toujours en Python3, mais au lieu de l'
__metaclass__
attribut, il faut utiliser lemetaclass
paramètre, comme dans:la source
La méta-programmation est amusante, mais peut se mettre en route. La plupart des solutions ici rendent difficile:
Donc, ma première suggestion est de suivre le chemin simple / explicite (fonctionne avec n'importe quel lanceur de test):
Comme nous ne devons pas nous répéter, ma deuxième suggestion s'appuie sur la réponse de @ Javier: adopter les tests basés sur les propriétés. Bibliothèque d'hypothèses:
a beaucoup plus de fonctionnalités intéressantes (statistiques, sortie de test supplémentaire, ...)
classe TestSequence (unittest.TestCase):
Pour tester vos exemples spécifiques, ajoutez simplement:
Pour exécuter un seul exemple particulier, vous pouvez commenter les autres exemples (l'exemple fourni sera exécuté en premier). Vous voudrez peut-être utiliser
@given(st.nothing())
. Une autre option consiste à remplacer le bloc entier par:Ok, vous n'avez pas de noms de test distincts. Mais peut-être avez-vous juste besoin de:
Exemple plus drôle
la source
Super tard pour la fête, mais j'ai eu du mal à les faire fonctionner pour
setUpClass
.Voici une version de la réponse de @ Javier qui donne
setUpClass
accès aux attributs alloués dynamiquement.Les sorties
la source
Juste pour jeter une autre solution dans le mix;)
C'est en fait le même que
parameterized
celui mentionné ci-dessus, mais spécifique àunittest
:Exemple d'utilisation:
la source
Outre l'utilisation de setattr, nous pouvons utiliser load_tests depuis python 3.2. Veuillez vous référer à l'article de blog blog.livreuro.com/en/coding/python/how-to-generate-discoverable-unit-tests-in-python-dynamically/
la source
Voici ma solution. Je trouve cela utile lorsque: 1. Devrait fonctionner pour unittest.Testcase et unittest découvrir 2. Avoir un ensemble de tests à exécuter pour différents réglages de paramètres. 3. Très simple pas de dépendance sur d'autres paquets
la source
la source