Python 单元测试:如何仅运行测试文件的一部分?
-
21-08-2019 - |
题
我有一个测试文件,其中包含花费大量时间的测试(它们将计算发送到集群并等待结果)。所有这些都在特定的 TestCase 类中。
由于它们需要时间而且不太可能中断,所以我希望能够选择这个测试子集是否运行(最好的方法是使用命令行参数,即“./tests.py --offline
“或类似的东西),这样我就可以经常、快速地运行大部分测试,并且当我有时间时,偶尔运行整个测试集。
目前,我只使用 unittest.main()
开始测试。
谢谢。
解决方案
默认 unittest.main()
使用默认的测试加载器从运行 main 的模块中创建一个 TestSuite。
您不必使用此默认行为。
例如,您可以制作三个 单元测试.TestSuite 实例。
“快速”子集。
fast = TestSuite() fast.addTests( TestFastThis ) fast.addTests( TestFastThat )
“慢”子集。
slow = TestSuite() slow.addTests( TestSlowAnother ) slow.addTests( TestSlowSomeMore )
“整套”。
alltests = unittest.TestSuite([fast, slow])
请注意,我已经调整了测试用例名称以指示“快速”与“快速”。慢的。您可以unittest.testloader子类别来解析类的名称并创建多个加载程序。
然后你的主程序可以解析命令行参数 优化分析 或者 arg解析 (自 2.7 或 3.2 起可用)选择您想要运行的套件,快速、慢速或全部。
或者,你可以相信 sys.argv[1]
是三个值之一并使用像这样简单的东西
if __name__ == "__main__":
suite = eval(sys.argv[1]) # Be careful with this line!
unittest.TextTestRunner().run(suite)
其他提示
实际上,可以通过测试情况下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
要具有这两种情况下测试
我使用一个简单的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 …
基本上你有两种方法可以做到这一点:
- 为班级定义您自己的测试套件
- 创建将返回实际数据的集群连接的模拟类。
我是第二种方法的坚定支持者;单元测试 应该 仅测试代码的特定单元,而不测试复杂的系统(例如数据库或集群)。但我明白这并不总是可能的;有时,创建模型的成本太高,或者测试的目标确实是在复杂的系统中。
回到选项(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
由于您使用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
或者你也可以利用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')
我找到了另一个解决方案,基于 unittest.skip
装饰工作品。通过设置 __unittest_skip__
和 __unittest_skip_why__
.
基于标签
我想应用一个标签系统,将一些测试标记为 quick
, slow
, glacier
, memoryhog
, cpuhog
, core
, , 等等。
然后运行 all 'quick' tests
, , 或者 run everything except 'memoryhog' tests
, ,您的基本白名单/黑名单设置
执行
我分两部分实现:
- 首先向测试添加标签(通过自定义
@testlabel
类装饰器) - 风俗
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
也有效
考虑使用专用的TestRunner,像py.test,鼻子或可能甚至zope.testing。它们都具有用于选择测试命令行选项。
我试过@洛特的回答是:
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)
我找到了另一种方法来选择 test_* 方法,我只想通过向它们添加属性来运行它们。您基本上使用元类来装饰 TestCase 类内的可调用对象,这些可调用对象具有带有 unittest.skip 装饰器的 StepDebug 属性。更多信息:
使用装饰器和元类跳过除 Python 中的单元测试之外的所有单元测试
我不知道这是否比上面的解决方案更好,我只是提供它作为一个选项。
还没有找到一个很好的方式前要做到这一点,所以在这里分享。
目标:获取一组测试文件一起,这样他们可以作为一个单元运行, 但我们仍然可以选择单独运行它们中的任何一个。
问题: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 )
这是只为我工作的事情。
if __name__ == '__main__':
unittest.main( argv=sys.argv, testRunner = unittest.TextTestRunner(verbosity=2))
当我把它叫做虽然我有在类和测试名称的名称来传递。有点不方便,因为我没有做类和测试名称组合记忆。
蟒./tests.py class_Name.test_30311
删除类名和测试名称运行在你的文件中的所有测试。我觉得这是更容易处理,然后内置的方法,因为我真的不改变对我的CLI命令。只需添加参数。
享受, 基思
我创建一个装饰,其允许用于标记测试作为慢测试和使用环境变量跳过他们
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