在我们的团队中,我们像这样定义大多数测试用例:

一个“框架”类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

并且让单元测试只运行testtishot ()

我怎样才能做到呢?

我试图重写if __name__ == "__main__":部分,但由于我是Python新手,我感到迷失,并继续猛冲到方法以外的所有东西。


当前回答

受到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 )

或者,您可以使用load_tests协议并在测试模块/文件中定义以下方法:

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() )

引用:

系统的问题。当unittest模块在脚本中时,Argv [1] 是否有一种方法可以循环遍历并执行Python类中的所有函数? 在python中遍历类的所有成员变量


或者,对于最后一个主程序示例,在阅读unittest.main()方法实现后,我提出了以下变化:

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() )

其他回答

如果你查看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
```lang-none

It does not require you to define a `unittest.main()` as the default behaviour of your module.

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

python mypkg/tests/test_module.py MyCase.testItIsHot

解释:

方便的方式 python myypkg /tests/test_module.py mycase . testtishot 会起作用,但是不言而喻的假设是您已经在您的测试文件中(通常在末尾)有这个常规的代码片段。 如果__name__ == "__main__": unittest.main () 不方便的方式 python -m unittest mypkg.tests.test_module.TestClass.test_method 总是可以工作,不需要你有if __name__ == "__main__": unittest.main()代码片段在你的测试源文件。

那么为什么第二种方法被认为不方便呢?因为这将是一个痛苦的<插入您的一个身体部位这里>键入长,点分隔的路径。而在第一种方法中,mypkg/tests/test_module.py部分可以由现代shell或您的编辑器自动完成。

受到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 )

或者,您可以使用load_tests协议并在测试模块/文件中定义以下方法:

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() )

引用:

系统的问题。当unittest模块在脚本中时,Argv [1] 是否有一种方法可以循环遍历并执行Python类中的所有函数? 在python中遍历类的所有成员变量


或者,对于最后一个主程序示例,在阅读unittest.main()方法实现后,我提出了以下变化:

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() )

如果你想直接从脚本(例如,从jupyter笔记本)运行测试,你可以这样做,只运行一个测试:

from testMyCase import MyCase
unittest.main(argv=['ignored', '-v', 'MyCase.testItIsHot'], exit=False)

如果你组织你的测试用例,也就是说,像实际代码一样遵循相同的组织,并且对相同包中的模块使用相对导入,你也可以使用以下命令格式:

python -m unittest mypkg.tests.test_module.TestClass.test_method

# In your case, this would be:
python -m unittest testMyCase.MyCase.testItIsHot

Python 3文档:命令行接口