web-dev-qa-db-ja.com

入れ子関数をモックする方法は?

私が使用しているモックライブラリは... モック です。

関数(レガシーコード)のテストケースを書き込もうとしたときに、この「モックネスト関数」の問題に遭遇しました。

この関数は、他のモジュールに大きく依存する非常に複雑なネストされた関数を使用していました。

ネストされた関数をmockでモックすることは可能かと思います。

22
satoru

たとえば、Google DRIVE APIからネストされた関数呼び出し(連鎖関数)をモックする必要があります

result = get_drive_service().files().insert(body='body', convert=True).execute()   

したがって、関数を介してパッチを適用する必要があります:service_mock()、files()、insert()、最後のexecute()応答まで:

from mock import patch
with patch('path.to.import.get_drive_service') as service_mock:
   service_mock.return_value.files.return_value.insert.\
   return_value.execute.return_value = {'key': 'value', 'status': 200}

主なスキーム:first .return_value。second .return_value。third .return_value。last .return_value = rsp

37
pymen

1つのオプションは、関数を変更して、オプションで呼び出す関数を受け入れるようにすることです。あなたが持っている場合:

def fn_to_test():
  def inner_fn():
    return 1
  return inner_fn() + 3

次のように変更します。

def fn_to_test( inner_fn = null )
  def inner_fn_orig():
    return 1
  if inner_fn==null:
    inner_fn = inner_fn_orig
  return fn() + 3

次に、「実際の」使用は正しい内部関数を取得し、テストでは独自の関数を提供できます。

fn_to_test() # calls the real inner function
def my_inner_fn():
  return 3
fn_to_test( inner_fn=my_inner_fn ) # calls the new version

これを行うこともできます:

def fn_to_test():
  def inner_fn_orign():
    return 1
  inner_fn = inner_fn_orig
  try:
    inner_fn = fn_to_test.inner_fn
  excecpt AttributeError:
    pass
  return inner_fn() + 3

このようにして、オーバーライドを定義するだけです。

fn_to_test() # calls the real inner function
def my_inner_fn():
  return 3
fn_to_test.inner_fn = my_inner_fn
fn_to_test() # calls the new version
5

これが行われるのを私が見た唯一の方法は、外部関数のコピーを動的に作成し、モックされた関数のコードで関数のコードオブジェクト定数を変更することです。

ネストされた関数に同等のオーバーライドが存在しますか?

2
Matthew Trevor

ネストされた関数をモックオブジェクトに置き換えようとしていますか?もしそうなら、関数がどれほど複雑であっても、それはかなり簡単です。 MagicMock を使用して、ほとんどすべてのpythonオブジェクトを置き換えることができます。

何かを返す関数をシミュレートする必要がある場合は、MagicMockreturn_valueパラメーターを設定するだけです。次のようになります。

>>> super_nested_mock = mock.MagicMock()
>>> super_nested_mock.return_value = 42
>>> super_nested_mock()
42

ただし、super_nested関数を内部のどこかで呼び出す別のコードをテストしようとしていて、それをモックアウトしたい場合は、 patch を使用する必要があります。モックライブラリでは、次のようになります。

with patch('super_nested') as super_nested_mock:
    super_nested_mock.return_value = "A good value to test with"
    assert my_function_that_calls_super_nested(5) == 20

ここで、通常はsuper_nestedを呼び出すwithブロック内のすべてのものは、代わりにsuper_nested_mockを呼び出し、設定した値を返すだけです。

パッチ呼び出しに正確に何を入れる必要があるかには、微妙な点がいくつかあります。主に、テストしているモジュールがオブジェクトを認識できるように、オブジェクトにパッチを適用する必要があります。詳細な手順については、「 パッチを適用する場所 "」を参照してください。

1
Wilduck