通过命令行从unittest.TestCase运行单个测试


256

在我们的团队中,我们定义了大多数测试用例,如下所示:

一门“框架”课ourtcfw.py

import unittest

class OurTcFw(unittest.TestCase):
    def setUp:
        # something

    # other stuff that we want to use everywhere

还有很多测试用例,例如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()

当我编写新的测试代码并希望经常运行它并节省时间时,我要做的是在所有其他测试之前放置“ __”。但这很麻烦,使我从正在编写的代码中分散了注意力,并且由此产生的提交噪音实在令人讨厌。

因此,例如,当对进行更改时testItIsHot(),我希望能够做到这一点:

$ python testMyCase.py testItIsHot

unittest运行 testItIsHot()

我该如何实现?

我尝试重写该if __name__ == "__main__":部分,但是由于我是Python的新手,所以我迷失了方向,不停地尝试除方法之外的所有事情。

Answers:


311

这可以按照您的建议进行工作-您只需指定类名即可:

python testMyCase.py MyCase.testItIsHot

2
天啊!由于测试要在python2.6上运行(99%的时间我可以使用python2.7进行测试),所以我一直在看2.6.8文档,却错过了很多!:-)
Alois Mahdal

1
刚刚注意到,仅当该方法称为“ test *”时,此方法才有效,因此很遗憾,它不能偶尔用于通过重命名“禁用”的测试
Alois Mahdal 2013年

4
不适用于子目录中的测试-成熟的Python程序中最常见的情况。
汤姆·斯威利

4
@TomSwirly现在无法检查,但我认为您可以通过__init__.py在该目录(和子目录,如果有的话)内创建(空)并调用eg 来做到这一点。python test/testMyCase.py test.MyCase.testItIsHot
阿洛瓦·马哈德

1
当我这样做时,什么也没有发生。我找到了解决方法,但我希望这种方法对我有用。
Joe Flack

152

如果您组织测试用例,即遵循与实际代码相同的组织,并且对同一包中的模块使用相对导入

您还可以使用以下命令格式:

python -m unittest mypkg.tests.test_module.TestClass.test_method
# In your case, this would be:
python -m unittest testMyCase.MyCase.testItIsHot

与此相关的Python3文档:https ://docs.python.org/3/library/unittest.html#command-line-interface


这是如此笨拙的Java风格。“ long_module_name.SameLongNameAsAClass.test_long_name_beginning_with_test_as_a_convention” ...更好地希望您不要像一个理智的人那样模块化到测试他们的代码的套件中。
约书亚·德特维尔

69

您可以猜到它可以很好地工作

python testMyCase.py MyCase.testItIsHot

还有另一种方法可以测试testItIsHot

    suite = unittest.TestSuite()
    suite.addTest(MyCase("testItIsHot"))
    runner = unittest.TextTestRunner()
    runner.run(suite)

11
我发现此答案的第二部分非常有用:我正在Eclipse + PyDev中编写测试,并且我不想切换到命令行!
Giovanni Di Milia

25

如果您查看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

它不需要您将a定义unittest.main()为模块的默认行为。


2
+1以来术语可能,如果新会混淆的语言(和usage甚至是奇怪的不一致):运行 python -m unittest module_test.TestClass.test_method假定一个文件module_test.py(从当前目录运行;而__init.py__要求); 并module_test.py包含class TestClass(unittest.TestCase)...其中包含的内容def test_method(self,...)(这对我在python 2.7.13上也适用)
michael

10

也许对某人会有帮助。如果您只想运行特定类的测试:

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

它在python 3.6中对我有用


3

@yarkee的启发,我将其与已经获得的一些代码结合在一起。您也可以从另一个脚本中调用此方法,run_unit_tests()而无需调用命令行即可直接调用该函数,也可以仅通过命令行从中调用它python3 my_test_file.py

import my_test_file
my_test_file.run_unit_tests()

可悲的是,这仅适用于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")

跑步者代码:

#! /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()

稍微编辑一下代码,您可以传递一个包含您要调用的所有单元测试的数组:

...
def run_unit_tests(unit_tests_to_run):
    runner = unittest.TextTestRunner()

    classes = \
    [
        LineBalancingUnitTests,
    ]

    runner.run( suite( classes, unit_tests_to_run ) )
...

和另一个文件:

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 )

或者,您可以使用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

如果要将执行限制为单个测试文件,则只需将测试发现模式设置为定义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() )

参考文献:

  1. 单元测试模块在脚本中时,sys.argv [1]有问题
  2. 有没有办法遍历并执行Python类中的所有功能?
  3. 在python中遍历一个类的所有成员变量

除了最后一个主程序示例,在阅读unittest.main()方法实现后,我想到了以下变体:

  1. https://github.com/python/cpython/blob/master/Lib/unittest/main.py#L65
#! /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() )

3

TL; DR:这很可能会起作用:

python mypkg/tests/test_module.py MyCase.testItIsHot

说明

  • 便捷的方式

    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()在测试源文件中包含该代码段。

那么为什么第二种方法不方便?因为手动键入该长的,用点分隔的路径会很麻烦(_ 在此处插入您的身体部位之一)。在第一种方法中,mypkg/tests/test_module.py可以使用现代外壳或编辑器自动完成零件。

PS:如果您认为身体部位在腰部以下,那么您就是一个真实的人。:-)我的意思是说“手指关节”。打字过多对您的关节不利。;-)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.