简体   繁体   English

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

[英]Running a single test from unittest.TestCase via the command line

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, I do 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, for example, when making changes to testItIsHot() , I want to be able to do this:因此,例如,在对testItIsHot()进行更改时,我希望能够做到这一点:

$ python testMyCase.py testItIsHot

and have unittest run only testItIsHot()并让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 新手,所以我感到迷茫,并不断抨击方法以外的所有内容。

这按您的建议工作 - 您只需要指定类名:

python testMyCase.py MyCase.testItIsHot

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

Python 3 documentation for this: Command-Line Interface用于此的 Python 3 文档: 命令行界面

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)

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
```lang-none

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

In case you want to run only tests from a specific class:如果您只想运行来自特定类的测试:

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

It works for me in Python 3.6.它在 Python 3.6 中对我有用。

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.testItIsHot

    would 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_method

    would always work, without requiring you to have that if __name__ == "__main__": unittest.main() code snippet in your test source file. if __name__ == "__main__": unittest.main()代码片段在您的测试源文件中,它将始终有效,而无需您拥有它。

So why is the second method considered inconvenient?那么为什么第二种方法被认为不方便呢? Because it would be a pain in the <insert one of your body parts here> to type that long, dot-delimited path by hand.因为在<在此处插入您的身体部位之一> 中手动键入以点分隔的长路径会很痛苦。 While in the first method, the mypkg/tests/test_module.py part can be auto-completed, either by a modern shell, or by your editor.在第一种方法中, mypkg/tests/test_module.py部分可以通过现代 shell 或您的编辑器自动完成。

Inspired by yarkee , I combined it with some of the code I already got.受到yarkee 的启发,我将它与我已经得到的一些代码结合起来。 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 .您也可以从另一个脚本调用它,只需调用函数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.3 or above:遗憾的是,这仅适用于 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 load_tests Protocol and define the following method in your test module/file:或者,您可以使用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

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:参考:

  1. Problem with sys.argv[1] when unittest module is in a script 当 unittest 模块在脚本中时,sys.argv[1] 出现问题
  2. Is there a way to loop through and execute all of the functions in a Python class? 有没有办法循环并执行 Python 类中的所有函数?
  3. looping over all member variables of a class in python 在python中循环一个类的​​所有成员变量

Alternatively, to the last main program example, I came up with the following variation after reading the unittest.main() method implementation:或者,对于最后一个主程序示例,我在阅读unittest.main()方法实现后想出了以下变体:

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

If you want to run the test directly from a script (for example, from a jupyter notebook), you can do this to run just one test:如果您想直接从脚本(例如,从 jupyter notebook)运行测试,您可以这样做以仅运行一个测试:

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

What worked for me was:对我有用的是:

cd project_dir
python -m unittest -v path\to\test\testMyCase.py -k my_test_name

-v is for unittest verbose log output. -v 用于 unittest 详细日志输出。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 通过命令行从unittest.TestCase运行单个测试 - 使用ddt - Running single test from unittest.TestCase via command line - with ddt Python,单元测试 - 将命令行参数传递给 unittest.TestCase 的设置 - Python, unit test - Pass command line arguments to setUp of unittest.TestCase 是否可以从 python unittest.TestCase 运行单个测试方法并引用该方法? - Is it possible to run a single test method from a python unittest.TestCase with a reference to the method? 从unittest.TestCase继承以实现非测试功能 - Inheriting from unittest.TestCase for non-test functionality 运行所有使用..import导入的unittest.TestCase * - Running all unittest.TestCase imported using from .. import * Django 测试运行器不尊重 unittest.TestCase? - Django test runner not respecting unittest.TestCase? 来自unittest.TestCase的tearDownClass的工作流程如何? - How is the workflow of tearDownClass from unittest.TestCase? 为什么要继承自unittest.TestCase? - Why inherit from unittest.TestCase? 从 unittest.TestCase 切换到 tf.test.TestCase 后的幻像测试 - Phantom tests after switching from unittest.TestCase to tf.test.TestCase Selenium python如何使用来自unittest.TestCase的assertEqual方法“没有这样的测试方法 <class 'unittest.case.TestCase'> ” - Selenium python how to use assertEqual method from unittest.TestCase “No such test method in <class 'unittest.case.TestCase'>”
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM