81

我有一个测试文件,其中包含需要花费大量时间的测试(它们将计算发送到集群并等待结果)。所有这些都在特定的 TestCase 类中。

由于它们需要时间而且不太可能中断,我希望能够选择这个测试子集是否运行(最好的方法是使用命令行参数,即“ ./tests.py --offline”或其他东西像那样),所以我可以经常快速地运行大部分测试,并且在我有时间的时候不时地运行整套测试。

现在,我只是unittest.main()用来开始测试。

4

16 回答 16

91

要仅运行单个特定测试,您可以使用:

python -m unittest test_module.TestClass.test_method

更多信息在这里

于 2013-07-23T17:48:07.207 回答
53

默认unittest.main()使用默认测试加载器从运行 main 的模块中创建一个 TestSuite。

您不必使用此默认行为。

例如,您可以创建三个unittest.TestSuite实例。

  1. “快速”子集。

    fast = TestSuite()
    fast.addTests(TestFastThis)
    fast.addTests(TestFastThat)
    
  2. “慢”子集。

    slow = TestSuite()
    slow.addTests(TestSlowAnother)
    slow.addTests(TestSlowSomeMore)
    
  3. “整体”套装。

    alltests = unittest.TestSuite([fast, slow])
    

请注意,我已经调整了 TestCase 名称以指示 Fast vs. Slow。您可以继承 unittest.TestLoader 来解析类的名称并创建多个加载器。

然后,您的主程序可以使用optparseargparse(自 2.7 或 3.2 起可用)解析命令行参数,以选择您要运行的套件,快速、慢速或全部。

或者,您可以相信这sys.argv[1]是三个值之一,并使用像这样简单的东西

if __name__ == "__main__":
    suite = eval(sys.argv[1])  # Be careful with this line!
    unittest.TextTestRunner().run(suite)
于 2009-07-01T10:23:27.817 回答
23

我正在使用一个简单的方法来做到这一点skipIf

import os

SLOW_TESTS = int(os.getenv('SLOW_TESTS', '0'))

@unittest.skipIf(not SLOW_TESTS, "slow")
class CheckMyFeature(unittest.TestCase):
    def runTest(self):
        …

这样我只需要用这一行来装饰一个已经存在的测试用例(不需要创建测试套件或类似的东西,只需os.getenv()在我的单元测试文件开头的一个调用行),并且默认情况下会跳过这个测试。

如果我想在速度很慢的情况下执行它,我只需像这样调用我的脚本:

SLOW_TESTS=1 python -m unittest …
于 2017-06-28T13:35:14.210 回答
13

实际上,可以将测试用例的名称作为 sys.argv 传递,并且只有这些用例才会被测试。

例如,假设你有

class TestAccount(unittest.TestCase):
    ...

class TestCustomer(unittest.TestCase):
    ...

class TestShipping(unittest.TestCase):
    ...

account = TestAccount
customer = TestCustomer
shipping = TestShipping

你可以打电话

python test.py account

只有账户测试,甚至

$ python test.py account customer

测试两种情况

于 2012-10-02T18:28:18.757 回答
11

你基本上有两种方法来做到这一点:

  1. 为班级定义自己的测试套件
  2. 创建将返回实际数据的集群连接的模拟类。

我是第二种方法的坚定支持者;单元测试应该只测试一个非常单元的代码,而不是复杂的系统(如数据库或集群)。但我知道这并不总是可能的;有时,创建模型实在是太昂贵了,或者测试的目标实际上是在复杂的系统中。

回到选项(1),您可以这样进行:

suite = unittest.TestSuite()
suite.addTest(MyUnitTestClass('quickRunningTest'))
suite.addTest(MyUnitTestClass('otherTest'))

然后将套件传递给测试运行器:

unittest.TextTestRunner().run(suite)

有关 python 文档的更多信息:http: //docs.python.org/library/unittest.html#testsuite-objects

于 2009-07-01T10:12:52.893 回答
8

由于您使用unittest.main(),您可以运行python tests.py --help以获取文档:

Usage: tests.py [options] [test] [...]

Options:
  -h, --help       Show this message
  -v, --verbose    Verbose output
  -q, --quiet      Minimal output
  -f, --failfast   Stop on first failure
  -c, --catch      Catch control-C and display results
  -b, --buffer     Buffer stdout and stderr during test runs

Examples:
  tests.py                               - run default set of tests
  tests.py MyTestSuite                   - run suite 'MyTestSuite'
  tests.py MyTestCase.testSomething      - run MyTestCase.testSomething
  tests.py MyTestCase                    - run all 'test*' test methods
                                           in MyTestCase

也就是说,你可以简单地做

python tests.py TestClass.test_method
于 2014-06-26T10:10:49.227 回答
6

根据unittest.skip装饰器的工作方式,我找到了另一个解决方案。通过设置__unittest_skip____unittest_skip_why__

基于标签

我想应用一个标记系统,将一些测试标记为quickslowglaciermemoryhogcpuhogcore等等。

然后运行all 'quick' tests,或者run everything except 'memoryhog' tests,您的基本白名单/黑名单设置

执行

我分两部分实现了这一点:

  1. 首先为测试添加标签(通过自定义@testlabel类装饰器)
  2. 自定义unittest.TestRunner以确定要跳过哪些测试,并在执行前修改测试列表内容。

工作实现在这个要点中: https ://gist.github.com/fragmuffin/a245f59bdcd457936c3b51aa2ebb3f6c

(一个完整的例子太长了,不能放在这里。)

结果是...

$ ./runtests.py --blacklist foo
test_foo (test_things.MyTest2) ... ok
test_bar (test_things.MyTest3) ... ok
test_one (test_things.MyTests1) ... skipped 'label exclusion'
test_two (test_things.MyTests1) ... skipped 'label exclusion'

----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK (skipped=2)

所有MyTests1类测试都被跳过,因为它有foo标签。

--whitelist也有效

于 2018-01-11T11:55:26.700 回答
3

我创建了一个装饰器,允许将测试标记为慢速测试并使用环境变量跳过它们

from unittest import skip
import os

def slow_test(func):
    return skipIf('SKIP_SLOW_TESTS' in os.environ, 'Skipping slow test')(func)

现在你可以像这样将你的测试标记为慢:

@slow_test
def test_my_funky_thing():
    perform_test()

SKIP_SLOW_TESTS并通过设置环境变量跳过慢速测试:

SKIP_SLOW_TESTS=1 python -m unittest
于 2019-02-13T15:12:09.047 回答
2

或者您可以使用该unittest.SkipTest()功能。skipOrRunTest例如,向您的测试类添加一个方法,如下所示:

def skipOrRunTest(self,testType):
    #testsToRun = 'ALL'
    #testsToRun = 'testType1, testType2, testType3, testType4,...etc'
    #testsToRun = 'testType1'
    #testsToRun = 'testType2'
    #testsToRun = 'testType3'
    testsToRun = 'testType4'              
    if ((testsToRun == 'ALL') or (testType in testsToRun)):
        return True 
    else:
        print "SKIPPED TEST because:\n\t testSuite '" + testType  + "' NOT IN testsToRun['" + testsToRun + "']" 
        self.skipTest("skipppy!!!")

然后在每个单元测试的最开始添加对这个 skipOrRunTest 方法的调用,如下所示:

def testType4(self):
    self.skipOrRunTest('testType4')
于 2013-06-13T21:46:36.983 回答
1

考虑使用专用的测试运行程序,例如py.testNose甚至可能是zope.testing。它们都有用于选择测试的命令行选项。

以鼻子为例。

于 2009-07-01T09:51:09.410 回答
1

我试过S.Lott 的回答

if __name__ == "__main__":
    suite = eval(sys.argv[1])  # Be careful with this line!
    unittest.TextTestRunner().run(suite)

但这给了我以下错误:

Traceback (most recent call last):
  File "functional_tests.py", line 178, in <module>
    unittest.TextTestRunner().run(suite)
  File "/usr/lib/python2.7/unittest/runner.py", line 151, in run
    test(result)
  File "/usr/lib/python2.7/unittest/case.py", line 188, in __init__
    testMethod = getattr(self, methodName)
TypeError: getattr(): attribute name must be string

以下对我有用:

if __name__ == "__main__":
    test_class = eval(sys.argv[1])
    suite = unittest.TestLoader().loadTestsFromTestCase(test_class)
    unittest.TextTestRunner().run(suite)
于 2015-12-08T02:04:02.180 回答
0

我找到了另一种方法来选择我只想通过向它们添加属性来运行的 test_* 方法。您基本上使用元类来装饰 TestCase 类中的可调用对象,这些对象具有 StepDebug 属性和 unittest.skip 装饰器。更多信息在:

通过使用装饰器和元类跳过所有单元测试,但 Python 中的一个

我不知道它是否比上述解决方案更好,我只是将其作为一个选项提供。

于 2015-05-12T09:58:50.120 回答
0

目标:将一组测试文件放在一起,以便它们可以作为一个单元运行,但我们仍然可以选择其中任何一个单独运行。

问题:discover 方法不允许轻松选择单个测试用例来运行。

设计:见下文。这会使命名空间变平,因此可以通过 TestCase 类名进行选择,并去掉“tests1.test_core”前缀:

./run-tests TestCore.test_fmap

代码

  test_module_names = [
    'tests1.test_core',
    'tests2.test_other',
    'tests3.test_foo',
    ]

  loader = unittest.defaultTestLoader
  if args:
    alltests = unittest.TestSuite()
    for a in args:
      for m in test_module_names:
        try:
          alltests.addTest( loader.loadTestsFromName( m + '.' + a ) )
        except AttributeError as e:
          continue
  else:
    alltests = loader.loadTestsFromNames( test_module_names )

  runner = unittest.TextTestRunner( verbosity = opt.verbose )
  runner.run( alltests )
于 2015-10-14T18:01:27.917 回答
0

这是唯一对我有用的东西。

if __name__ == '__main__':
    unittest.main(argv=sys.argv, testRunner = unittest.TextTestRunner(verbosity=2))

当我调用它时,我必须传入类名和测试名。有点不方便,因为我没有记住班级和测试名称的组合。

python ./tests.py class_Name.test_30311

删除名和测试名会运行文件中的所有测试。我发现这比内置方法更容易处理,因为我并没有真正更改 CLI 上的命令只需添加参数。

于 2017-02-14T23:28:52.413 回答
0

我发现这个答案试图弄清楚如何运行特定类别的测试;例如,

class TestCase1(unittest.TestCase):
    def some_test(self):
        self.assertEqual(True, True)

class TestCase2(unittest.TestCase):
    def some_other_test(self):
        self.assertEqual(False, False)

我想要一种快速注释的方法,TestCase1或者TestCase2不涉及我扫描选择 100 多行代码,我最终找到了这个:

if __name__ == "__main__":
    tests = []
    tests.append("TestCase1")
    # tests.append("TestCase2")
    unittest.main(defaultTest=tests)

它只是使用unittest.main()'sdefaultTest参数来指定要运行的测试类。

于 2021-01-12T15:41:40.090 回答
0

有时我会手动运行每个测试功能。说我的测试课看起来像这样......

class TestStuff(unittest.TestCase):
    def test1():
    def test2():

然后我运行这个...

t = TestStuff()
t.test1()
t.test2()

(我使用 Spyder IDE 进行数据分析,这可能不适合带有更流畅测试工具的 IDE)

于 2021-07-22T19:40:22.693 回答