100 votes

Python unittest passant des arguments

En Python, comment puis-je passer un argument de la ligne de commande à une fonction unittest ?

Voici le code jusqu'à présent Je sais que c'est faux.

class TestingClass(unittest.TestCase):

    def testEmails(self):
        assertEqual(email_from_argument, "my_email@example.com")

if __name__ == "__main__":
    unittest.main(argv=[sys.argv[1]])
    email_from_argument = sys.argv[1]

166voto

hwjp Points 3041

Alors les médecins ici présents disent : "Vous dites que ça fait mal ? Alors ne le faites pas !" ont probablement raison. Mais si vous voulez vraiment le faire, voici une façon de passer des arguments à un test unittest :

import sys
import unittest

class MyTest(unittest.TestCase):
    USERNAME = "jemima"
    PASSWORD = "password"

    def test_logins_or_something(self):
        print('username:', self.USERNAME)
        print('password:', self.PASSWORD)

if __name__ == "__main__":
    if len(sys.argv) > 1:
        MyTest.USERNAME = sys.argv.pop()
        MyTest.PASSWORD = sys.argv.pop()
    unittest.main()

Cela vous permettra de courir avec :

python mytests.py myusername mypassword

Vous avez besoin de la argv.pop s, afin que vos paramètres de ligne de commande ne perturbent pas ceux d'unittest...

Vous pouvez également envisager d'utiliser des variables d'environnement :

import os
import unittest

class MyTest(unittest.TestCase):
    USERNAME = "jemima"
    PASSWORD = "password"

    def test_logins_or_something(self):
        print('username:', self.USERNAME)
        print('password:', self.PASSWORD)

if __name__ == "__main__":
    MyTest.USERNAME = os.environ.get('TEST_USERNAME', MyTest.USERNAME)
    MyTest.PASSWORD = os.environ.get('TEST_PASSWORD', MyTest.PASSWORD)
    unittest.main()

Cela vous permettra de courir avec :

TEST_USERNAME=ausername TEST_PASSWORD=apassword python mytests.py

Et cela a l'avantage de ne pas perturber l'analyse des arguments d'unittest. L'inconvénient est que ça ne fonctionnera pas tout à fait comme ça sous Windows...

36voto

steffens21 Points 679

Une autre méthode pour ceux qui veulent vraiment le faire malgré les remarques correctes que vous ne devriez pas :

import unittest

class MyTest(unittest.TestCase):

    def __init__(self, testName, extraArg):
        super(MyTest, self).__init__(testName)  # calling the super class init varies for different python versions.  This works for 2.7
        self.myExtraArg = extraArg

    def test_something(self):
        print(self.myExtraArg)

# call your test
suite = unittest.TestSuite()
suite.addTest(MyTest('test_something', extraArg))
unittest.TextTestRunner(verbosity=2).run(suite)

13voto

Federico Points 1525

Même si les gourous du test disent que nous ne devrions pas le faire : je le fais. Dans certains contextes, il est très utile de disposer de paramètres pour orienter le test dans la bonne direction, par exemple :

  • Parmi la douzaine de cartes USB identiques, laquelle dois-je utiliser pour ce test maintenant ?
  • quel serveur dois-je utiliser pour ce test maintenant ?
  • Quel XXX dois-je utiliser ?

Pour moi, l'utilisation de la variable d'environnement est suffisante pour cette puprose car vous n'avez pas à écrire de code dédié pour faire passer vos paramètres ; c'est supporté par Python. C'est propre et simple.

Bien sûr, je ne plaide pas en faveur de tests entièrement paramétrables. Mais nous devons être pragmatiques et, comme je l'ai dit, dans certains contextes, vous avez besoin d'un paramètre ou deux. Nous ne devrions pas en abuser :)

import os
import unittest

class MyTest(unittest.TestCase):
    def setUp(self):
        self.var1 = os.environ["VAR1"]
        self.var2 = os.environ["VAR2"]

    def test_01(self):
        print("var1: {}, var2: {}".format(self.var1, self.var2))

Puis, à partir de la ligne de commande (testé sous Linux)

$ export VAR1=1
$ export VAR2=2
$ python -m unittest MyTest
var1: 1, var2: 2
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

4voto

sfinkens Points 491

Si vous voulez utiliser L'approche de steffens21 con unittest.TestLoader vous pouvez modifier le chargeur de test d'origine (cf. unittest.py ) :

import unittest
from unittest import suite

class TestLoaderWithKwargs(unittest.TestLoader):
    """A test loader which allows to parse keyword arguments to the
       test case class."""
    def loadTestsFromTestCase(self, testCaseClass, **kwargs):
        """Return a suite of all tests cases contained in 
           testCaseClass."""
        if issubclass(testCaseClass, suite.TestSuite):
            raise TypeError("Test cases should not be derived from "\
                            "TestSuite. Maybe you meant to derive from"\ 
                            " TestCase?")
        testCaseNames = self.getTestCaseNames(testCaseClass)
        if not testCaseNames and hasattr(testCaseClass, 'runTest'):
            testCaseNames = ['runTest']

        # Modification here: parse keyword arguments to testCaseClass.
        test_cases = []
        for test_case_name in testCaseNames:
            test_cases.append(testCaseClass(test_case_name, **kwargs))
        loaded_suite = self.suiteClass(test_cases)

        return loaded_suite 

# call your test
loader = TestLoaderWithKwargs()
suite = loader.loadTestsFromTestCase(MyTest, extraArg=extraArg)
unittest.TextTestRunner(verbosity=2).run(suite)

1voto

Denis Solovev Points 61

J'ai le même problème. Ma solution est la suivante : après avoir géré l'analyse des arguments en utilisant argparse ou d'une autre manière, supprimez les arguments de sys.argv :

sys.argv = sys.argv[:1]  

Si vous en avez besoin, vous pouvez filtrer les arguments unittest de main.parseArgs().

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X