Python unittest传递参数


77

在python中,我如何将命令行中的参数传递给unittest函数。这是到目前为止的代码……我知道这是错误的。

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] 

7
问题是,单元测试应该能够自动运行,这使得传递参数变得困难。也许,如果您对要测试的内容进行了更多解释,可以吗?
kojiro

1
当您在命令行中运行时,可以运行python testfunction.py,并且名称==“ main”允许这样做。我希望能够运行python testfunction.py my_email@example.com my_email2@example.com
Christopher H

1
如何使用配置文件?那会有用吗?例如,鼻子TestConfig
kojiro 2012年

1
我不想...只是一个偏爱,但也许我应该
Christopher H

Answers:


142

因此,这里的医生说:“你说那很疼?那就不要那样做!” 可能是对的。但是,如果您确实愿意,这是将参数传递给单元测试的一种方法:

import sys
import unittest

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

    def test_logins_or_something(self):
        print('username : {}'.format(self.USERNAME))
        print('password : {}'.format(self.PASSWORD))


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

这将使您可以:

python mytests.py ausername apassword

您需要argv.pops,以便您的命令行参数不会与unittest自己的混乱。

[更新]您可能要研究的另一件事是使用环境变量:

import os
import unittest

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

    def test_logins_or_something(self):
        print('username : {}'.format(self.USERNAME))
        print('password : {}'.format(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()

这样您就可以运行:

TEST_USERNAME=ausername TEST_PASSWORD=apassword python mytests.py

而且它的优点是您不会搞砸unittest自己的参数解析。缺点是它在Windows上无法像...


看起来pytest页面已移动。现在位于docs.pytest.org
Evgen,

1
仅供参考,过去我做过这样的事情:使用“-”将我的参数与unittest可能需要的参数分开;然后我可以将参数“-”之后的参数列表传递给我自己的arg解析器,并将其从sys.argv中删除,或使用unittest.main(argv = smaller_list)显式传递args unittest可能需要的参数
Joshua Richardson

1
sys.argv.pop()方法似乎不适用于python3。我很想知道如何在中完成此操作python3
Yeow_Meng

2
@Yeow_Meng,您可能需要更具体。我将它与python-3.6.5一起使用,并且可以正常工作。
r2evans

如果要在不同的环境(例如不同的阶段等)上运行相同的测试,这将非常方便。环境变量可能是最干净的。
萨曼莎·阿特金斯

28

尽管您不应该做出正确的评论,但对于那些确实想要这样做的人来说,另一种方法是:

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)

好的例子!另一个在agiletesting.blogspot.com/2005/01/…上。但是,关心通过的论点不会
干扰单元测试的结果。– SIslam

谢谢。这有助于弄清楚如何使我的特殊情况下的单元测试有效。
Benny Jobigan '16

1
我可以批量吗?如果在MyTest类中有多个测试
Alex

请告诉我为什么您选择不使用unitest.main()而是使用TestSuite / TextTestRunner?
变量

6

即使测试专家说我们不应该这样做:我愿意。在某些情况下,有意义的是具有参数来朝正确的方向驱动测试,例如:

  • 我现在应该在十几个相同的USB卡中使用哪个进行测试?
  • 我现在应该使用哪个服务器进行此测试?
  • 我应该使用哪个XXX?

对我而言,使用环境变量足以满足此需求,因为您不必编写专用代码来传递参数。它受Python支持。干净简单。

当然,我不主张进行完全可参数化的测试。但是我们必须务实,正如我所说,在某些情况下,您需要一个或两个参数。我们不应该反对它:)

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))

然后从命令行(在Linux上测试)

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

OK

3

如果您想将steffens21的方法用于unittest.TestLoader,则可以修改原始的测试加载器(请参阅参考资料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)

1
self.getTestCaseNames方法从哪里来?
Alex

它属于TestLoaderWithKwargs继承的unittest.TestLoader类。
sfinkens

1

有同样的问题。我的解决方案是使用argparse或其他方式处理参数解析后,从sys.argv中删除参数

sys.argv = sys.argv[:1]  

如果需要,可以从main.parseArgs()过滤unittest参数


-3

单元测试旨在测试非常基本的功能(应用程序的最低级别的功能),以确保您的应用程序构建块正常工作。确切含义可能没有正式定义,但是您应该考虑使用其他类型的测试来获得更大的功能-请参阅集成测试。单元测试框架可能不是理想的选择。


6
是的,但是可以使用unittest框架本身(在很多情况下使用)来开发和集成测试框架,而这通常需要复杂的设置和拆卸。在这种情况下,如果可能的话,拥有一个带有测试函数和参数的基类,以及一个带有参数定义的继承类,或者使用基于环境的配置脚本,将很有帮助。
Umar
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.