web-dev-qa-db-ja.com

pytestフィクスチャに引数を渡すことはできますか?

私のすべてのテストのベースラインは、少なくとも1人の乗客が乗るタクシーが常に存在するということです。私はいくつかの基本的な備品でこのセットアップを簡単に達成することができます:

from blah import Passenger, Taxi

@pytest.fixture
def passenger():
    return Passenger()

@pytest.fixture
def taxi(passenger):
    return Taxi(rear_seat=passenger)

ベースラインのテストは簡単です。

def test_taxi_contains_passenger(taxi)
    assert taxi.has_passenger()

より複雑なテスト設定が必要になると、問題が発生します。タクシーに複数の乗客がいる必要があるシナリオと、乗客の属性を定義する必要があるシナリオがあります。例えば:

def test_three_passengers_in_taxi(taxi)
    assert taxi.has_passengers(3)
    assert taxi.front_passenger_is_not_a_child()

特定のテスト用に特定のフィクスチャを用意することで、この問題を回避できます。上記のテストでは、次のフィクスチャを作成します。

@pytest.fixture
def three_passenger_test_setup(taxi)
    taxi.add_front_seat_passenger(Passenger(child=False))
    taxi.add_rear_seat_passenger(Passenger())
    return taxi

上記のフィクスチャをテストケースに渡すことができ、すべてがダンディですが、このルートをたどると、すべてのテストにフィクスチャができてしまう可能性があり、これを行うためのより効率的な方法があるはずだと感じています。

フィクスチャに引数を渡して、フィクスチャが返すオブジェクトの作成にそれらの引数を使用できるようにする方法はありますか?テスト関数をパラメーター化する必要がありますか?フィクスチャ?それとも私は時間を無駄にしていて、テストごとのフィクスチャは行く方法ですか?

7
pyzzled

これを行うには、フィクスチャ内で引数を取り、フィクスチャからメソッドを返すメソッドを使用します。

例を示しましょう

@pytest.fixture
def my_fixture():

  def _method(a, b):
    return a*b

  return _method

def test_me(my_fixture):
  result1 = my_fixture(2, 3)
  assert result1 == 6

  result2 = my_fixture(4, 5)
  assert result2 == 20
19
supamaze

フィクスチャに引数を渡して、フィクスチャが返すオブジェクトの作成にそれらの引数を使用できるようにする方法はありますか?テスト関数をパラメーター化する必要がありますか?

indirect=Trueでテストパラメータ化を使用できます。 pytestのドキュメント: 特定の引数に間接的に適用 。ここに表示されているように: https://stackoverflow.com/a/33879151/3858507


フィクスチャ?

適している可能性のある別のオプションは、パラメーター化を使用して引数を指定するフィクスチャを使用することです。

@pytest.fixture(params=[3,4])
def number_of_passengers(request):
    return request.param

次に、タクシーとテスト自体からこの器具にアクセスします。

@pytest.fixture
def taxi(number_of_passengers):
    return Taxi(rear_seat=Passenger() * number_of_passengers)

def test_three_passengers_in_taxi(taxi, number_of_passengers)
    assert taxi.has_passengers(number_of_passengers)
    assert taxi.front_passenger_is_not_a_child()

この方法は、テストとアサーションがケース間で非常に類似している場合に適しています。


それとも私は時間を無駄にしていて、テストごとのフィクスチャは行く方法ですか?

間違いなくすべてのテスト関数のフィクスチャを作成するべきではないと思います。そのためには、セットアップをテスト内に置くだけです。これは、タクシーのさまざまなケースに対してさまざまなアサーションを作成する必要がある場合に、実際に実行可能な代替手段です。


そして最後に、使用できるもう1つの可能なパターンは、タクシー工場です。提示した例ではあまり役に立ちませんが、複数のパラメーターが必要で、一部のみが変更されている場合は、次のようなフィクスチャーを作成できます。

from functools import partial
@pytest.fixture
def taxi_factory():
    return partial(Taxi, 1, 2, 3)
8
nitzpo

そのfixtureは単なるPythonデコレータです。

@decorator
def function(args):
  ...

のための空想です

def function(args):
  ...
function = decorator(function)

したがって、独自のデコレータを記述して、デコレーションしたい関数を必要なものにまとめることができるかもしれませんandfixture

def myFixture(parameter):
  def wrapper(function):
    def wrapped(*args, **kwargs):
      return function(parameter, *args, **kwargs)
    return wrapped
  return pytest.fixture(wrapper)

@myFixture('foo')
def function(parameter, ...):
  ...

これはfixtureのように機能しますが、値('foo')as parameter to function

1
Alfe