92

在 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]
4

7 回答 7

156

所以这里的医生说“你说那很痛?那就不要那样做!” 可能是对的。但是,如果您真的想要,这是将参数传递给单元测试测试的一种方法:

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

这将让你运行:

python mytests.py myusername mypassword

您需要argv.pops,因此您的命令行参数不会与 unittest 自己的参数混淆...

您可能想要研究的另一件事是使用环境变量:

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

这将让你运行:

TEST_USERNAME=ausername TEST_PASSWORD=apassword python mytests.py

它的优点是你不会弄乱 unittest 自己的参数解析。缺点是它不会像在 Windows 上那样工作......

于 2013-12-20T11:47:58.530 回答
34

对于那些真正想要这样做的人的另一种方法,尽管你不应该有正确的评论:

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)
于 2014-04-28T21:43:40.480 回答
12

即使测试大师说我们不应该这样做:我愿意。在某些情况下,使用参数来推动测试朝着正确的方向发展是很有意义的,例如:

  • 我现在应该使用十几个相同的 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
于 2017-10-13T14:26:22.560 回答
4

如果您想使用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)
于 2016-06-20T07:22:26.280 回答
1

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

sys.argv = sys.argv[:1]  

如果需要,可以从 main.parseArgs() 过滤单元测试参数。

于 2017-04-12T09:55:02.967 回答
0

这是我的解决方案:

# your test class
class TestingClass(unittest.TestCase):

    # This will only run once for all the tests within this class
    @classmethod
    def setUpClass(cls) -> None:
       if len(sys.argv) > 1:
          cls.email = sys.argv[1]

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


if __name__ == "__main__":
    unittest.main()

你可以有一个这样的runner.py文件:

# your runner.py
loader = unittest.TestLoader()
tests = loader.discover('.') # note that this will find all your tests, you can also provide the name of the package e.g. `loader.discover('tests')
runner = unittest.TextTestRunner(verbose=3)
result = runner.run(tests

使用上面的代码,您应该使用runner.py my_email@example.com.

于 2021-02-11T18:43:17.063 回答
-5

单元测试旨在测试非常基本的功能(应用程序的最低级别功能),以确保您的应用程序构建块正常工作。对于这究竟意味着什么,可能没有正式的定义,但是您应该考虑对更大的功能进行其他类型的测试——请参阅集成测试。单元测试框架可能不适合此目的。

于 2012-07-08T08:51:28.460 回答