Python単体テスト:テストファイルの一部だけを実行するにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/1068246

質問

かなりの時間のかかるテスト (計算をクラスターに送信し、結果を待つテスト) を含むテスト ファイルがあります。これらはすべて、特定の TestCase クラス内にあります。

これらは時間がかかり、さらに中断する可能性が低いため、このテストのサブセットを実行するか実行しないかを選択できるようにしたいと考えています (最良の方法は、コマンドライン引数を使用することです。./tests.py --offline" など)、ほとんどのテストを頻繁かつ迅速に実行し、時間があるときにセット全体を時々実行することができました。

今のところ、私はただ使っています unittest.main() テストを開始します。

ありがとう。

役に立ちましたか?

解決

デフォルト unittest.main() デフォルトのテストローダーを使用して、main が実行されているモジュールから TestSuite を作成します。

このデフォルトの動作を使用する必要はありません。

たとえば、3つ作ることができます ユニットテスト.TestSuite インスタンス。

  1. 「高速」サブセット。

    fast = TestSuite()
    fast.addTests( TestFastThis )
    fast.addTests( TestFastThat )
    
  2. 「遅い」サブセット。

    slow = TestSuite()
    slow.addTests( TestSlowAnother )
    slow.addTests( TestSlowSomeMore )
    
  3. 「全体」セット。

    alltests = unittest.TestSuite([fast, slow])
    

Fast と TestCase を示すために TestCase 名を調整したことに注意してください。遅い。Subclass Unittest.testloaderは、クラスの名前を解析し、複数のローダーを作成できます。

その後、メインプログラムは次のようにコマンドライン引数を解析できます。 オプトパース または 引数解析 (2.7 または 3.2 以降で利用可能) 高速、低速、またはすべてを実行するスイートを選択します。

あるいは、それを信頼してもいいでしょう sys.argv[1] は 3 つの値のいずれかであり、これと同じくらい単純なものを使用します

if __name__ == "__main__":
    suite = eval(sys.argv[1])  # Be careful with this line!
    unittest.TextTestRunner().run(suite)

他のヒント

特定のテストを 1 つだけ実行するには、以下を使用できます。

$ python -m unittest test_module.TestClass.test_method

詳しくは ここ

実際には、テスト ケースの名前を sys.argv として渡すことができ、それらのケースのみがテストされます。

たとえば、

class TestAccount(unittest.TestCase):
    ...

class TestCustomer(unittest.TestCase):
    ...

class TestShipping(unittest.TestCase):
    ...

account = TestAccount
customer = TestCustomer
shipping = TestShipping

電話をかけることができます

python test.py account

アカウントテストのみを行うことも、さらには

$ python test.py account customer

両方のケースをテストしてもらう

私は単純な方法を使用してこれを行っています skipIf:

import os

SLOW_TESTS = int(os.getenv('SLOW_TESTS', '0'))

@unittest.skipIf(not SLOW_TESTS, "slow")
class CheckMyFeature(unittest.TestCase):
    def runTest(self):
        …

この方法では、既存のテスト ケースをこの 1 行で装飾するだけで済みます (テスト スイートなどを作成する必要はなく、その 1 つだけです) os.getenv() 単体テスト ファイルの先頭にある呼び出し行)、デフォルトとして、このテストはスキップされます。

遅いにもかかわらず実行したい場合は、次のようにスクリプトを呼び出すだけです。

SLOW_TESTS=1 python -m unittest …

基本的に次の 2 つの方法があります。

  1. クラス用に独自のテスト スイートを定義する
  2. 実際のデータを返すクラスター接続のモック クラスを作成します。

私は彼の 2 番目のアプローチを強く支持します。単体テスト すべき 複雑なシステム (データベースやクラスターなど) ではなく、コードのまさに単位のみをテストします。しかし、それが常に可能であるとは限らないことは理解しています。場合によっては、モックアップの作成にコストがかかりすぎたり、テストの目標が実際には複雑なシステムにある場合もあります。

オプション (1) に戻り、次の方法で続行できます。

suite = unittest.TestSuite()
suite.addTest(MyUnitTestClass('quickRunningTest'))
suite.addTest(MyUnitTestClass('otherTest'))

そしてスイートをテストランナーに渡します。

unittest.TextTestRunner().run(suite)

Python のドキュメントに関する詳細情報: http://docs.python.org/library/unittest.html#testsuite-objects

使っているので、 unittest.main() ただ走ることができます python tests.py --help ドキュメントを入手するには:

Usage: tests.py [options] [test] [...]

Options:
  -h, --help       Show this message
  -v, --verbose    Verbose output
  -q, --quiet      Minimal output
  -f, --failfast   Stop on first failure
  -c, --catch      Catch control-C and display results
  -b, --buffer     Buffer stdout and stderr during test runs

Examples:
  tests.py                               - run default set of tests
  tests.py MyTestSuite                   - run suite 'MyTestSuite'
  tests.py MyTestCase.testSomething      - run MyTestCase.testSomething
  tests.py MyTestCase                    - run all 'test*' test methods
                                               in MyTestCase

つまり、単純に行うことができます

python tests.py TestClass.test_method

または、 unittest.SkipTest() 関数。例: を追加します。 skipOrRunTest 次のようにテストクラスにメソッドを追加します。

def skipOrRunTest(self,testType):
    #testsToRun = 'ALL'
    #testsToRun = 'testType1, testType2, testType3, testType4,...etc'
    #testsToRun = 'testType1'
    #testsToRun = 'testType2'
    #testsToRun = 'testType3'
    testsToRun = 'testType4'              
    if ((testsToRun == 'ALL') or (testType in testsToRun)):
        return True 
    else:
        print "SKIPPED TEST because:\n\t testSuite '" + testType  + "' NOT IN testsToRun['" + testsToRun + "']" 
        self.skipTest("skipppy!!!")

次に、この SkipOrRunTest メソッドへの呼び出しを、次のように各単体テストの先頭に追加します。

def testType4(self):
    self.skipOrRunTest('testType4')

私は別の解決策を見つけました。 unittest.skip デコレーター作品。を設定することで、 __unittest_skip__ そして __unittest_skip_why__.

ラベルベース

ラベル付けシステムを適用して、いくつかのテストに次のようなラベルを付けたいと考えていました。 quick, slow, glacier, memoryhog, cpuhog, core, 、 等々。

それから実行します all 'quick' tests, 、 または run everything except 'memoryhog' tests, 、基本的なホワイトリスト/ブラックリスト設定

実装

これを 2 つの部分に分けて実装しました。

  1. まず、ラベルをテストに追加します (カスタム @testlabel クラスデコレータ)
  2. カスタム unittest.TestRunner スキップするテストを特定し、実行前にテストリストの内容を変更します。

実用的な実装は次の要点にあります。https://gist.github.com/fragmuffin/a245f59bdcd457936c3b51aa2ebb3f6c

(完全に動作する例は長すぎてここに載せられません)

結果は…

$ ./runtests.py --blacklist foo
test_foo (test_things.MyTest2) ... ok
test_bar (test_things.MyTest3) ... ok
test_one (test_things.MyTests1) ... skipped 'label exclusion'
test_two (test_things.MyTests1) ... skipped 'label exclusion'

----------------------------------------------------------------------
Ran 4 tests in 0.000s

OK (skipped=2)

全て MyTests1 クラステストはスキップされます。 foo ラベル。

--whitelist も機能します

py.test、nose、場合によっては zope.testing などの専用のテストランナーの使用を検討してください。これらにはすべて、テストを選択するためのコマンド ライン オプションがあります。

たとえば、Nose を見てください。 https://pypi.python.org/pypi/nose/1.3.0

@slottの答えを試してみました:

if __name__ == "__main__":
    suite = eval(sys.argv[1])  # Be careful with this line!
    unittest.TextTestRunner().run(suite)

しかし、それにより次のエラーが発生しました。

Traceback (most recent call last):
  File "functional_tests.py", line 178, in <module>
    unittest.TextTestRunner().run(suite)
  File "/usr/lib/python2.7/unittest/runner.py", line 151, in run
    test(result)
  File "/usr/lib/python2.7/unittest/case.py", line 188, in __init__
    testMethod = getattr(self, methodName)
TypeError: getattr(): attribute name must be string

以下は私にとってうまくいきました:

if __name__ == "__main__":
    test_class = eval(sys.argv[1])
    suite = unittest.TestLoader().loadTestsFromTestCase(test_class)
    unittest.TextTestRunner().run(suite)

属性を追加することで、実行したいだけの test_* メソッドを選択する別の方法を見つけました。基本的に、メタクラスを使用して、StepDebug 属性を持つ TestCase クラス内の呼び出し可能オブジェクトを、unittest.skip デコレータで装飾します。詳細については、

デコレータとメタクラスを使用して、Python で 1 つを除くすべての単体テストをスキップする

上記の解決策よりも優れているかどうかはわかりませんが、オプションとして提供しているだけです。

これまでこれを行う良い方法が見つからなかったので、ここで共有します。

ゴール:テストファイルのセットを一緒に取得して、ユニットとして実行できるようにしますが、いずれかを選択して自分で実行することができます。

問題:Discover メソッドでは、実行する単一のテスト ケースを簡単に選択できません。

デザイン:以下を参照してください。これ 平らにする 名前空間なので、TestCase クラス名で選択でき、「tests1.test_core」プレフィックスは省略します。

./run-tests TestCore.test_fmap

コード

  test_module_names = [
    'tests1.test_core',
    'tests2.test_other',
    'tests3.test_foo',
    ]

  loader = unittest.defaultTestLoader
  if args:
    alltests = unittest.TestSuite()
    for a in args:
      for m in test_module_names:
        try:
          alltests.addTest( loader.loadTestsFromName( m+'.'+a ) )
        except AttributeError as e:
          continue
  else:
    alltests = loader.loadTestsFromNames( test_module_names )

  runner = unittest.TextTestRunner( verbosity = opt.verbose )
  runner.run( alltests )

これが私にとって唯一うまくいったことです。

if __name__ == '__main__':
unittest.main( argv=sys.argv, testRunner = unittest.TextTestRunner(verbosity=2))

ただし、それを呼び出すときは、クラス名とテスト名を渡す必要がありました。クラスとテスト名の組み合わせを覚えていないので少し不便です。

python ./tests.py クラス名.test_30311

クラス名とテスト名を削除すると、ファイル内のすべてのテストが実行されます。CLI でコマンドを実際に変更しないため、組み込みメソッドよりもこの方がはるかに簡単に対処できることがわかりました。パラメータを追加するだけです。

お楽しみください、キース

テストを遅いテストとしてマークし、環境変数を使用してスキップできるデコレータを作成しました。

from unittest import skip
import os

def slow_test(func):
    return skipIf('SKIP_SLOW_TESTS' in os.environ, 'Skipping slow test')(func)

次のように、テストを遅いとマークできるようになりました。

@slow_test
def test_my_funky_thing():
    perform_test()

を設定することで遅いテストをスキップします。 SKIP_SLOW_TESTS 環境変数:

SKIP_SLOW_TESTS=1 python -m unittest
ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top