Python 的单元测试可以像鼻子一样并行测试吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4710142/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Can Python's unittest test in parallel, like nose can?
提问by Oddthinking
Python's NOSE testing framework has the concept of running multiple tests in parallel.
Python 的 NOSE 测试框架具有并行运行多个测试的概念。
The purpose of this is not to test concurrency in the code, but to make tests for code that has "no side-effects, no ordering issues, and no external dependencies" run faster. The performance gain comes from concurrent I/O waits when they are accessing different devices, better use of multi CPUs/cores, and by running time.sleep() statements in parallel.
这样做的目的不是测试代码中的并发性,而是让“没有副作用、没有排序问题、没有外部依赖”的代码测试运行得更快。性能提升来自于访问不同设备时的并发 I/O 等待、更好地利用多 CPU/内核以及并行运行 time.sleep() 语句。
I believe the same thing could be done with Python's unittest testing framework, by having a plugin Test Runner.
我相信通过使用插件 Test Runner 可以使用 Python 的 unittest 测试框架完成同样的事情。
Has anyone had any experience with such a beast, and can they make any recommendations?
有没有人对这样的野兽有任何经验,他们可以提出任何建议吗?
采纳答案by dietbuddha
Python unittest's builtin testrunner does not run tests in parallel. It probably wouldn't be too hard write one that did. I've written my own just to reformat the output and time each test. That took maybe 1/2 a day. I think you can swap out the TestSuite class that is used with a derived one that uses multiprocess without much trouble.
Python unittest 的内置 testrunner 不会并行运行测试。写一个这样做可能不会太难。我自己写的只是为了重新格式化输出和每次测试的时间。这可能需要每天 1/2。我认为您可以将使用的 TestSuite 类替换为使用多进程的派生类,而不会有太多麻烦。
回答by Joe
The testtoolspackage is an extension of unittest which supports running tests concurrently. It can be used with your old test classes that inherit unittest.TestCase.
所述testtools包是运行测试单元测试并发支持的扩展。它可以与继承unittest.TestCase.
For example:
例如:
import unittest
import testtools
class MyTester(unittest.TestCase):
# Tests...
suite = unittest.TestLoader().loadTestsFromTestCase(MyTester)
concurrent_suite = testtools.ConcurrentStreamTestSuite(lambda: ((case, None) for case in suite))
concurrent_suite.run(testtools.StreamResult())
回答by prathik shirolkar
If this is what you did initially
如果这是您最初所做的
runner = unittest.TextTestRunner()
runner.run(suite)
-----------------------------------------
-----------------------------------------
replace it with
将其替换为
from concurrencytest import ConcurrentTestSuite, fork_for_tests
concurrent_suite = ConcurrentTestSuite(suite, fork_for_tests(4))
runner.run(concurrent_suite)
回答by u6390868
Please use pytest-xdist, if you want parallel run.
如果您想要并行运行,请使用pytest-xdist。
The pytest-xdist plugin extends py.test with some unique test execution modes:
- test run parallelization: if you have multiple CPUs or hosts you can use those for a combined test run. This allows to speed up development or to use special resources of remote machines.
[...]
pytest-xdist 插件使用一些独特的测试执行模式扩展了 py.test:
- 测试运行并行化:如果您有多个 CPU 或主机,您可以将它们用于组合测试运行。这允许加速开发或使用远程机器的特殊资源。
[...]
More info: Rohan Dunham's blog
更多信息:Rohan Dunham 的博客
回答by Shin
If you only need Python3 suport, consider using my fastunit.
如果您只需要 Python3 支持,请考虑使用我的fastunit。
I just change few code of unittest, making test case run as coroutines.
我只是更改了 unittest 的一些代码,使测试用例作为协程运行。
It really saved my time.
它真的节省了我的时间。
I just finished it last week, and may not testing enough, if any error happens, please let me know, so that I can make it better, thanks!
我上周刚完成,可能测试不够,如果有任何错误,请告诉我,以便我改进,谢谢!
回答by yakaboskic
Another option that might be easier, if you don't have that many test cases and they are not dependent, is to kick off each test case manually in a separate process.
如果您没有那么多测试用例并且它们不相互依赖,另一个可能更简单的选择是在单独的过程中手动启动每个测试用例。
For instance, open up a couple tmux sessions and then kick off a test case in each session using something like:
例如,打开几个 tmux 会话,然后使用以下内容在每个会话中启动一个测试用例:
python -m unittest -v MyTestModule.MyTestClass.test_n
回答by xxks-kkk
You can override the unittest.TestSuiteand implement some concurrency paradigm. Then, you use your customized TestSuiteclass just like normal unittest. In the following example, I implement my customized TestSuiteclass using async:
您可以覆盖unittest.TestSuite并实现一些并发范例。然后,您可以像平常一样使用您的自定义TestSuite类unittest。在以下示例中,我TestSuite使用以下方法实现我的自定义类async:
import unittest
import asyncio
class CustomTestSuite(unittest.TestSuite):
def run(self, result, debug=False):
"""
We override the 'run' routine to support the execution of unittest in parallel
:param result:
:param debug:
:return:
"""
topLevel = False
if getattr(result, '_testRunEntered', False) is False:
result._testRunEntered = topLevel = True
asyncMethod = []
loop = asyncio.new_event_loop()
asyncio.set_event_loop(loop)
for index, test in enumerate(self):
asyncMethod.append(self.startRunCase(index, test, result))
if asyncMethod:
loop.run_until_complete(asyncio.wait(asyncMethod))
loop.close()
if topLevel:
self._tearDownPreviousClass(None, result)
self._handleModuleTearDown(result)
result._testRunEntered = False
return result
async def startRunCase(self, index, test, result):
def _isnotsuite(test):
"A crude way to tell apart testcases and suites with duck-typing"
try:
iter(test)
except TypeError:
return True
return False
loop = asyncio.get_event_loop()
if result.shouldStop:
return False
if _isnotsuite(test):
self._tearDownPreviousClass(test, result)
self._handleModuleFixture(test, result)
self._handleClassSetUp(test, result)
result._previousTestClass = test.__class__
if (getattr(test.__class__, '_classSetupFailed', False) or
getattr(result, '_moduleSetUpFailed', False)):
return True
await loop.run_in_executor(None, test, result)
if self._cleanup:
self._removeTestAtIndex(index)
class TestStringMethods(unittest.TestCase):
def test_upper(self):
self.assertEqual('foo'.upper(), 'FOO')
def test_isupper(self):
self.assertTrue('FOO'.isupper())
self.assertFalse('Foo'.isupper())
def test_split(self):
s = 'hello world'
self.assertEqual(s.split(), ['hello', 'world'])
# check that s.split fails when the separator is not a string
with self.assertRaises(TypeError):
s.split(2)
if __name__ == '__main__':
suite = CustomTestSuite()
suite.addTest(TestStringMethods('test_upper'))
suite.addTest(TestStringMethods('test_isupper'))
suite.addTest(TestStringMethods('test_split'))
unittest.TextTestRunner(verbosity=2).run(suite)
In the main, I just construct my customized TestSuiteclass CustomTestSuite, add all the test cases, and finally run it.
在 中main,我只是构建了我的自定义TestSuite类CustomTestSuite,添加了所有测试用例,最后运行它。

