Python 通过命令行从 unittest.TestCase 运行单个测试
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/15971735/
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
Running single test from unittest.TestCase via command line
提问by Alois Mahdal
In our team, we define most test cases like this:
在我们的团队中,我们定义大多数测试用例是这样的:
One "framework" class ourtcfw.py:
一个“框架”类ourtcfw.py:
import unittest
class OurTcFw(unittest.TestCase):
def setUp:
# something
# other stuff that we want to use everywhere
and a lot of test cases like testMyCase.py:
以及很多测试用例,比如 testMyCase.py:
import localweather
class MyCase(OurTcFw):
def testItIsSunny(self):
self.assertTrue(localweather.sunny)
def testItIsHot(self):
self.assertTrue(localweather.temperature > 20)
if __name__ == "__main__":
unittest.main()
When I'm writing new test code and want to run it often, and save time, what I do is that I put "__" in front of all other tests. But it's cumbersome, distracts me from the code I'm writing and the commit noise this creates is plain annoying.
当我正在编写新的测试代码并希望经常运行它并节省时间时,我所做的是将“__”放在所有其他测试的前面。但它很麻烦,分散了我正在编写的代码的注意力,并且由此产生的提交噪音很烦人。
So e.g. when making changes to testItIsHot(), I want to be able to do this:
因此,例如在对 进行更改时testItIsHot(),我希望能够做到这一点:
$ python testMyCase.py testItIsHot
and have unittestrun onlytestItIsHot()
并unittest运行只testItIsHot()
How can I achieve that?
我怎样才能做到这一点?
I tried to rewrite the if __name__ == "__main__":part, but since I'm new to Python, I'm feeling lost and keep bashing into everything else than the methods.
我试图重写这if __name__ == "__main__":部分,但由于我是 Python 的新手,我感到迷茫,并继续抨击除方法之外的所有其他内容。
采纳答案by phihag
This works as you suggest - you just have to specify the class name as well:
这按您的建议工作 - 您只需要指定类名:
python testMyCase.py MyCase.testItIsHot
回答by Yarkee
It can work well as you guess
它可以像你猜的那样工作
python testMyCase.py MyCase.testItIsHot
And there is another way to just test testItIsHot:
还有另一种方法来测试testItIsHot:
suite = unittest.TestSuite()
suite.addTest(MyCase("testItIsHot"))
runner = unittest.TextTestRunner()
runner.run(suite)
回答by Ajay M
If you organize your test cases, that is, follow the same organization like the actual code and also use relative imports for modules in the same package
如果您组织测试用例,即遵循与实际代码相同的组织方式,并且对同一包中的模块也使用相对导入
You can also use the following command format:
您还可以使用以下命令格式:
python -m unittest mypkg.tests.test_module.TestClass.test_method
# In your case, this would be:
python -m unittest testMyCase.MyCase.testItIsHot
Python3 documentation for this: https://docs.python.org/3/library/unittest.html#command-line-interface
用于此的 Python3 文档:https://docs.python.org/3/library/unittest.html#command-line-interface
回答by skqr
If you check out the help of the unittest module it tells you about several combinations that allow you to run test case classes from a module and test methods from a test case class.
如果您查看 unittest 模块的帮助,它会告诉您几种组合,这些组合允许您从模块运行测试用例类和从测试用例类运行测试方法。
python3 -m unittest -h
[...]
Examples:
python3 -m unittest test_module - run tests from test_module
python3 -m unittest module.TestClass - run tests from module.TestClass
python3 -m unittest module.Class.test_method - run specified test method
It does not require you to define a unittest.main()as the default behaviour of your module.
它不需要您将 a 定义unittest.main()为模块的默认行为。
回答by user
Inspired by @yarkeeI combined it with some of the code I already got. You can also call this from another script, just by calling the function run_unit_tests()without requiring to use the command line, or just call it from the command line with python3 my_test_file.py.
受@yarkee 的启发,我将它与我已经得到的一些代码结合起来。您也可以从另一个脚本调用它,只需调用该函数run_unit_tests()而不需要使用命令行,或者只需从命令行调用它python3 my_test_file.py。
import my_test_file
my_test_file.run_unit_tests()
Sadly this only works for Python 3.3or superior:
可悲的是,这仅适用于Python 3.3或优于:
import unittest
class LineBalancingUnitTests(unittest.TestCase):
@classmethod
def setUp(self):
self.maxDiff = None
def test_it_is_sunny(self):
self.assertTrue("a" == "a")
def test_it_is_hot(self):
self.assertTrue("a" != "b")
Runner code:
跑步者代码:
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import unittest
from .somewhere import LineBalancingUnitTests
def create_suite(classes, unit_tests_to_run):
suite = unittest.TestSuite()
unit_tests_to_run_count = len( unit_tests_to_run )
for _class in classes:
_object = _class()
for function_name in dir( _object ):
if function_name.lower().startswith( "test" ):
if unit_tests_to_run_count > 0 \
and function_name not in unit_tests_to_run:
continue
suite.addTest( _class( function_name ) )
return suite
def run_unit_tests():
runner = unittest.TextTestRunner()
classes = [
LineBalancingUnitTests,
]
# Comment all the tests names on this list, to run all Unit Tests
unit_tests_to_run = [
"test_it_is_sunny",
# "test_it_is_hot",
]
runner.run( create_suite( classes, unit_tests_to_run ) )
if __name__ == "__main__":
print( "\n\n" )
run_unit_tests()
Editing the code a little, you can pass an array with all unit tests you would like to call:
稍微编辑代码,您可以传递一个包含所有要调用的单元测试的数组:
...
def run_unit_tests(unit_tests_to_run):
runner = unittest.TextTestRunner()
classes = \
[
LineBalancingUnitTests,
]
runner.run( suite( classes, unit_tests_to_run ) )
...
And another file:
另一个文件:
import my_test_file
# Comment all the tests names on this list, to run all Unit Tests
unit_tests_to_run = \
[
"test_it_is_sunny",
# "test_it_is_hot",
]
my_test_file.run_unit_tests( unit_tests_to_run )
Alternatively, you can use https://docs.python.org/3/library/unittest.html#load-tests-protocoland define the following method on your test module/file:
或者,您可以使用https://docs.python.org/3/library/unittest.html#load-tests-protocol并在您的测试模块/文件上定义以下方法:
def load_tests(loader, standard_tests, pattern):
suite = unittest.TestSuite()
# To add a single test from this file
suite.addTest( LineBalancingUnitTests( 'test_it_is_sunny' ) )
# To add a single test class from this file
suite.addTests( unittest.TestLoader().loadTestsFromTestCase( LineBalancingUnitTests ) )
return suite
If you want to limit the execution to one single test file, you just need to set the test discovery pattern to the only file where you defined the load_tests()function.
如果您想将执行限制为单个测试文件,您只需要将测试发现模式设置为您定义该load_tests()函数的唯一文件。
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import unittest
test_pattern = 'mytest/module/name.py'
PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.realpath( __file__ ) )
loader = unittest.TestLoader()
start_dir = os.path.join( PACKAGE_ROOT_DIRECTORY, 'testing' )
suite = loader.discover( start_dir, test_pattern )
runner = unittest.TextTestRunner( verbosity=2 )
results = runner.run( suite )
print( "results: %s" % results )
print( "results.wasSuccessful: %s" % results.wasSuccessful() )
sys.exit( not results.wasSuccessful() )
References:
参考:
- Problem with sys.argv[1] when unittest module is in a script
- Is there a way to loop through and execute all of the functions in a Python class?
- looping over all member variables of a class in python
Alternatively to the last main program example, I came up with the following variation after reading the unittest.main()method implementation:
作为最后一个主程序示例的替代方案,我在阅读unittest.main()方法实现后想出了以下变体:
#! /usr/bin/env python3
# -*- coding: utf-8 -*-
import os
import sys
import unittest
PACKAGE_ROOT_DIRECTORY = os.path.dirname( os.path.realpath( __file__ ) )
start_dir = os.path.join( PACKAGE_ROOT_DIRECTORY, 'testing' )
from testing_package import main_unit_tests_module
testNames = ["TestCaseClassName.test_nameHelloWorld"]
loader = unittest.TestLoader()
suite = loader.loadTestsFromNames( testNames, main_unit_tests_module )
runner = unittest.TextTestRunner(verbosity=2)
results = runner.run( suite )
print( "results: %s" % results )
print( "results.wasSuccessful: %s" % results.wasSuccessful() )
sys.exit( not results.wasSuccessful() )
回答by Bohdan
Maybe, it will be helpful for somebody. In case you want to run only tests from specific class:
也许,这对某人有帮助。如果您只想运行来自特定类的测试:
if __name__ == "__main__":
unittest.main(MyCase())
It works for me in python 3.6
它在 python 3.6 中对我有用
回答by RayLuo
TL;DR: This would very likely work:
TL;DR:这很可能会奏效:
python mypkg/tests/test_module.py MyCase.testItIsHot
The explanation:
解释:
The convenient way
python mypkg/tests/test_module.py MyCase.testItIsHotwould work BUT its unspoken assumption is you already have this conventional code snippet inside (typically at the end of) your test file.
if __name__ == "__main__": unittest.main()The inconvenient way
python -m unittest mypkg.tests.test_module.TestClass.test_methodwould always work, without requiring you to have that
if __name__ == "__main__": unittest.main()code snippet in your test source file.
方便的方式
python mypkg/tests/test_module.py MyCase.testItIsHot会起作用,但它不言而喻的假设是您的测试文件中(通常在末尾)已经有了这个传统的代码片段。
if __name__ == "__main__": unittest.main()不方便的方式
python -m unittest mypkg.tests.test_module.TestClass.test_method将始终有效,而无需您
if __name__ == "__main__": unittest.main()在测试源文件中包含该代码片段。
So why does the 2nd method considered inconvenient? Because it would be a pain in the (_ insert one of your body part here_) to type that long, dot-delimited path by hand. While in 1st method, the mypkg/tests/test_module.pypart can be auto-completed, either by a modern shell, or by your editor.
那么为什么第二种方法被认为不方便呢?因为在(_在此处插入您的身体部位之一_)中手动键入以点分隔的长路径会很麻烦。在第一种方法中,该mypkg/tests/test_module.py部分可以通过现代 shell 或您的编辑器自动完成。
PS: If you thought that body partis somewhere below your waist, you are an authentic person. :-) I mean to say "finger joint". Too much typing would be bad for your joints. ;-)
PS:如果你认为身体部位在你的腰部以下,那你就是一个真实的人。:-) 我的意思是说“手指关节”。打字太多对你的关节不利。;-)

