web-dev-qa-db-ja.com

unittest対pytest

Unittestでは、クラス内の変数を設定でき、このクラスのメソッドは使用する変数を選択できます...

class test_class(unittest.TestCase):
    def setUp(self):        
        self.varA = 1
        self.varB = 2
        self.varC = 3
        self.modified_varA = 2

    def test_1(self):
        do_something_with_self.varA, self.varB

    def test_2(self):
        do_something_with_self_modified_varA, self.varC

そのため、unittestでは、1つのクラスの下にあるテストをまとめて、さまざまなメソッドにさまざまな変数(varAとvarB)を使用することが簡単でした。 pytestでは、unittestのクラスではなく、conftest.pyに次のようにフィクスチャを作成しました...

@pytest.fixture(scope="module")
def input1():
    varA = 1
    varB = 2
    return varA, varB

@pytest.fixture(scope="module")
def input2():
    varA = 2
    varC = 3
    return varA, varC

このinput1とinput2を、2つの異なる関数の異なるファイル(たとえばtest_this.py)の関数にフィードします。上記の情報に基づく質問は次のとおりです...

  1. このファイルを単にインポートすることはできないため、conftest.pyでローカル変数を宣言することはできないためです。 test_this.pyの異なる関数で使用できる異なる変数をここで宣言するより良い方法はありますか?これらの変数の実際のテストには5つの異なる構成があり、conftest.pyの多くの異なるフィクスチャを定義し、test_this.pyの5つの異なる関数の関数引数として使用すると痛いので、ユニットテストクラス構造に戻り、定義します私の変数と私が欲しいものを選んでください

  2. Test_this.pyでグローバル変数を宣言し、必要な方法で関数で使用するだけですか? Pythonicではないようです。この変数は、このファイル内の関数によってのみ使用されます。

  3. Test_that.pyとtest_them.pyもあるとします。これらの異なるファイル間に共有変数がある場合、それらをどのように宣言しますか?これらのすべてのテストファイルがあるディレクトリに変数calle variables.pyを作成し、必要なときにいつでもインポートを実行しますか?これにより、すべてのデータを個別に保持できます。

  4. Pytestは、クラスを使用して関数を整理することを思いとどまっていますか?私がオンラインで読んだすべての例では、すべてがフィクスチャのみの多くの機能を使用しているようです。クラスとメソッドを定義し、pytestでテストを整理する構成とは何ですか?

  5. ある関数の結果を別の関数に使用する必要があるテストシナリオがあります。 pytestでは、戻り値ではなく関数の最後にアサートがあるため、この関数をフィクスチャとして使用することはできません。どうすればこれを達成できますか?これは、あるテストが別のテストに依存しているという良い習慣ではないことを知っていますが、回避策はありますか?

回答ありがとうございます。

34
LuckyStarr

1)まず、conftest.pyだけでなく、必要なすべてのpythonモジュールでこれらのフィクスチャを宣言できます。そのモジュールをインポートできます。また、フィクスチャを同じ方法で使用できますsetUpメソッドを使用したとき:

@pytest.fixture(scope='class')
def input(request):
    request.cls.varA = 1
    request.cls.varB = 2
    request.cls.varC = 3
    request.cls.modified_varA = 2

@pytest.usefixtures('input')
class TestClass:
    def test_1(self):
        do_something_with_self.varA, self.varB

    def test_2(self):
        do_something_with_self_modified_varA, self.varC

または、個別のフィクスチャで個別の変数を定義できます。

def fixture_a():
    return varA

def fixture_b():
    return varB

def fixture_c():
    return varC

def fixture_mod_A():
    return modified_varA

または、すべての変数を返す1つのフィクスチャを作成する(そうではないのですか?)か、選択によって変数を返す間接的なパラメータ化されたフィクスチャを作成する(非常に混乱する方法):

@pytest.fixture()
def parametrized_iput(request):
   vars = {'varA': 1, 'varB': 2, 'varC': 3}
   var_names = request.param
   return (vars[var_name] for var_name in var_names)

@pytest.mark.parametrize('parametrized_iput', [('varA', 'varC')], indirect=True)
def test_1(parametrized_iput)
   varA, varC = parametrized_iput
   ...

または、フィクスチャをオンザフライで作成するフィクスチャファクトリを作成することもできます。テストが5つと変数の構成が5つしかない場合は奇妙に聞こえますが、両方を何百も取得する場合は便利です。

3)もちろんできます。ただし、このファイルを直接インポートするのではなく、インポートするファイルを指定するコマンドラインオプションを使用することをお勧めします。この場合、コードを変更せずに変数で別のファイルを選択できます。

4)nosetestから移行したため、テストでクラスを使用します。 pytestでクラスを使用する際の問題については言及しませんでした。

5)その場合、私はあなたに以下を行うことを提案します:最初に目的のアクションで機能を作成します:

def some_actions(a, b):
    # some actions here
    ...
    return c

次に、テストとフィクスチャの両方で使用します。

def test():
    assert some_actions(1,2) == 10

@pytest.fixture()
def some_fixture():
     return some_actions(1,2)
25
Ilya Karpeev

Unittestは読みやすいと思います。新しいテスターに​​とって、unittestは本当に簡単です。箱から出してすぐに動作します。 Pythonの実装に依存しますが、今後数年間インターフェースが変更されることはありません。

私は、ファイルごとに最大1つのテストがあるようにテストを整理するのが好きです。その場合、私はクラスに依存しません...しかし、私はすべてのテストからクラスをインポートして何かをします。

一部のWebサイトでは、unittestの色について文句を言うことはできません。私のユニットテストはJenkinsなどのJUNIT出力レポートを作成するので、これは冗談だと思います。 JUNITをWebサイトに変換するための優れたツール(1ファイルでも)がありますが、これはテストツールの責任ではありません。

また、ユニットテストを開始するには多くのコードが必要であると不満を言う人もいます。私は同意しません、ユニットテストを作成するには4行のコードが必要です!しかし、Pytestはすべての難しい注釈を知る必要があります。これは単純なPython開発者にとっては普通ではありません。

また、重要な理由は、unittestが無料のままであることです。ただし、何らかの理由(bitbucketなど)でpytestを使用する場合は、テストを変換してコードを読みにくくするツールがあります。

楽しむ!

1
Bart Mensfort