コマンドラインを介してunittest.TestCaseから単一のテストを実行する


257

私たちのチームでは、ほとんどのテストケースを次のように定義しています。

「フレームワーク」クラス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に慣れていないので、道に迷って、メソッド以外のすべてに打ち込んでいます。

回答:


311

これはあなたが提案するように機能します-クラス名も指定するだけです:

python testMyCase.py MyCase.testItIsHot

2
あら!テストが(私は時間の99%のpython2.6上で実行されることになるので、できる python2.7でテスト自体をテストする)、私は2.6.8ドキュメントを見て、そんなに逃しました!:-)
アロア・マダル

1
これは、メソッドが「test *」と呼ばれる場合にのみ機能することに注意してください。そのため、残念ながら、名前を変更して「無効」になっているテストを実行することはできません
Alois Mahdal

4
サブディレクトリのテストでは機能しません-成熟したPythonプログラムで最も一般的なケースです。
トムスワーリー、2015

4
@TomSwirly今は確認できませんが__init__.py、ディレクトリ(およびサブディレクトリがある場合はサブディレクトリ)内に(空の)を作成し、たとえばを呼び出すことで確認できると思います。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" ...コードをテストする正気な人のようなスイートにモジュール化しないことをお勧めします。
Joshua Detwiler

69

それはあなたが推測するようにうまくいくことができます

python testMyCase.py MyCase.testItIsHot

そして単にテストする別の方法がありますtestItIsHot

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

11
この回答の2番目の部分は非常に役に立ちました。Eclipse+ PyDevでテストを作成していて、コマンドラインに切り替えたくありません。
Giovanni Di Milia 2013年

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

unittest.main()モジュールのデフォルトの動作としてaを定義する必要はありません。


2
+1と用語以来、言語に新しい場合は混乱(とすることが可能usageであっても奇妙な矛盾である):ランニングは、 python -m unittest module_test.TestClass.test_methodファイルを前提としmodule_test.py(現在のディレクトリから実行すると__init.py__されていない必要)。and module_test.pycontains class TestClass(unittest.TestCase)...contains def test_method(self,...)(これは私にもpython 2.7.13で動作します)
マイケル

11

多分、それは誰かのために役立つでしょう。特定のクラスのテストのみを実行したい場合:

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

実行を1つのテストファイルに制限する場合は、テスト検出パターンを、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. unittestモジュールがスクリプト内にある場合の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()テストソースファイルにそのコードスニペットがなくても、常に機能します。

では、なぜ2番目の方法が不便であると考えられるのでしょうか。長いドットで区切られたパスを手で入力するのは(_ 身体の一部をここに挿入 _)するのが面倒だからです。1つ目の方法では、mypkg/tests/test_module.pyパーツは最新のシェルまたはエディターによってオートコンプリートできます。

PS:体の一部が腰より下にあると思ったなら、あなたは本物の人です。:-)「指の関節」を意味します。タイピングが多すぎると、関節に悪影響を及ぼします。;-)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.