13

私はpythonunittestモジュールを使用していくつかのテストを行っています。ただし、それは非常に反復的です。

同じテストを何度も繰り返して、正しいかどうかを確認したいデータがたくさんあります。ただし、すべてのテストを定義する必要があります。

たとえば、私はこれに似た何かをしたいと思います。私はジェネレーターを使用してそれを行うことができることを知っています(ここの前のスレッドでそれを見つけました)。しかし、別のテストモジュールを使用することさえあるかもしれない代替案はありますか?

どんな提案も素晴らしいでしょう。


import unittest

class TestData(unittest.TestCase):
    def testNumbers(self):
        numbers = [0,11,222,33,44,555,6,77,8,9999]
        for i in numbers:
            self.assertEqual(i, 33)
4

7 に答える 7

11

Bill Gribbleによって提案されたソリューションのサンプルコードは、次のようになります。

import unittest

class DataTestCase(unittest.TestCase):
    def __init__(self, number):
        unittest.TestCase.__init__(self, methodName='testOneNumber')
        self.number = number

    def testOneNumber(self):
        self.assertEqual(self.number, 33)

    def shortDescription(self):
        # We need to distinguish between instances of this test case.
        return 'DataTestCase for number %d' % self.number


def get_test_data_suite():
    numbers = [0,11,222,33,44,555,6,77,8,9999]
    return unittest.TestSuite([DataTestCase(n) for n in numbers])

if __name__ == '__main__':
    testRunner = unittest.TextTestRunner()
    testRunner.run(get_test_data_suite())
于 2010-10-13T11:48:35.240 に答える
6

unittest.TestCase.subTest(msg=None, **params)Python 3.4以降、コンテキストマネージャー(ドキュメント)を使用できます。これにより、ステートメントを1つ追加するだけで、目的を達成できます。

これが使用するように変更された例ですsubTest()

import unittest

class TestData(unittest.TestCase):
    def testNumbers(self):
        numbers = [0, 11, 222, 33, 44, 555, 6, 77, 8, 9999]
        for i in numbers:
            with self.subTest(i=i):  # added statement
                self.assertEqual(i, 33)
于 2019-01-22T13:31:53.397 に答える
5

unittest.TestSuiteクラスの使用を検討することをお勧めします。これにより、個別に実行される一連のunittest.TestCaseインスタンスを動的に構築できます。unittest.TestCaseサブクラスは、1つのテストメソッドのみを定義する必要があります。クラスは、その特定のインスタンスに対してテストする値を渡す構築パラメーターを受け入れます。

于 2010-10-12T14:25:53.260 に答える
4

ddtライブラリは、あなたが求めているものを正確に解決するために構築されましたunittest[*]。

例えば:

import ddt
import unittest

@ddt.ddt
class EvalTests(unittest.TestCase):

    @ddt.data(
            ('1', 1),
            ('1 == 1',  True),
            ('1 == 2',  False),
            ('1 + 2',   4),  ## This will fail
    )
    def test_eval_expressions(self, case):
        expr, exp_value = case
        self.assertEqual(eval(expr), exp_value)

そして、それを実行すると、1つではなく4つのテストケースが得られます。

$ python -m unittest  -v  test_eval.py
test_eval_expressions_1___1___1_ (test_eval.EvalTests) ... ok
test_eval_expressions_2___1__1___True_ (test_eval.EvalTests) ... ok
test_eval_expressions_3___1__2___False_ (test_eval.EvalTests) ... ok
test_eval_expressions_4___1_2___4_ (test_eval.EvalTests) ... FAIL

======================================================================
FAIL: test_eval_expressions_4___1_2___4_ (test_eval.EvalTests)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/usr/lib/python/lib/site-packages/ddt.py", line 129, in wrapper
    return func(self, *args, **kwargs)
  File "/Work/test_eval.py", line 15, in test_eval_expressions
    self.assertEqual(eval(expr), exp_value)
AssertionError: 3 != 4

----------------------------------------------------------------------
Ran 4 tests in 0.002s

FAILED (failures=1)

ddtが生成されたTCの名前を考え出そうとしていることに注意してください。

pipでインストールします。

pip install ddt

[*] pythonicpytestフレームワーク(pytest.mark.parametrize)の同じソリューションがコアツールに統合されており、pytestこの機能だけに切り替える価値があります。

于 2016-08-09T18:14:15.853 に答える
2

ループでアサーションを実行する際の問題は、アサーションの1つが失敗した場合、どの値が原因であるかがわからないことです(この例では、失敗し0ますが、デバッグするまでわかりません)。一方、繰り返しself.assertEqual(i, 33)はコードの重複をもたらすため、さらに悪い考えです。

私がテストで行うことは、テスト内に単純な短い名前の内部関数を作成し、それをさまざまな引数で呼び出すことです。したがって、関数は次のようになります。

import unittest

class TestData(unittest.TestCase):
    def testNumbers(self):
        def eq(i):
            self.assertEqual(i, 33)
        eq(0)
        eq(11)
        eq(222)
        eq(33)
        eq(44)
        eq(555)
        ... 

このように、アサーションが失敗すると0、モジュールによって出力されたスタックトレースにすぐに表示されunittestます。

于 2010-10-12T13:59:36.987 に答える
2

別の投稿で、私はノーズテストに出くわし ました。それはデータ駆動型テストにより適しています。


class Test_data():
    def testNumbers():
        numbers = [0,11,222,33,44,555,6,77,8,9999]
        for i in numbers:
            yield checkNumber, num

def checkNumber(num):
    assert num == 33

上記のコードは、私の最初の投稿とまったく同じことをします。インポートは必要ありません。Pythonクラスを作成するだけです。

次のように入力してテストを実行します。

nosetests filename

于 2010-10-15T13:44:07.990 に答える
0

この答えのスピンオフ、それは私にとってはうまくいきませんでした。大量のデータを処理していない場合は、異なる入力で同じテストを実行する必要がありました。以下のテストは、私がカスタマイズしたいメソッドを使用create_aしています。create_b

要件は、同じカスタマイズで両方のテストを実行することです。

class Tests(unittest.TestCase):

    def test_a_uses_b(self):
        a = create_a()
        b = create_b()
        a.b = b
        self.assertIs(b.a, a)

    def test_b_uses_a(self):
        a = create_a()
        b = create_b()
        b.a = a
        self.assertIs(a.b, b)

テストローダーをバイパスしてインスタンス化するTestSuiteTestCase、と呼ばれる単一のメソッドが必要だったため、エラーが発生しましたrunTest

結果はこれでした:

class Tests(unittest.TestCase):

    def __init__(self, create_a, create_b):
        super().__init__()
        self.create_b = create_b
        self.create_a = create_a

    def test_a_uses_b(self):
        a = self.create_a()
        b = self.create_b()
        a.b = b
        self.assertIs(b.a, a)

    def test_b_uses_a(self):
        a = self.create_a()
        b = self.create_b()
        b.a = a
        self.assertIs(a.b, b)


class TestPair1(Tests):
    def __init__(self):
        super().__init__(create_a1, create_b1)


class TestPair2(Tests):
    def __init__(self):
        super().__init__(create_a2, create_b2)
于 2017-03-16T13:02:13.770 に答える