web-dev-qa-db-ja.com

Pythonのモックpatch.objectを使用して、別のメソッド内で呼び出されたメソッドの戻り値を変更する

私がテストしようとしている別の関数内で呼び出された関数の戻り値を模擬することは可能ですか?モックされたメソッド(テスト中の多くのメソッドで呼び出されます)が、呼び出されるたびに指定された変数を返すようにします。例えば:

class Foo:
    def method_1():
       results = uses_some_other_method()
    def method_n():
       results = uses_some_other_method()

単体テストでは、モックを使用してuses_some_other_method()の戻り値を変更し、Fooで呼び出されるたびに、@patch.object(...)で定義したものを返すようにします。

51
mdoc-2011

これを行うには2つの方法があります。パッチおよびpatch.objectを使用

パッチは、オブジェクトを直接インポートするのではなく、次のようにテストしているオブジェクトによって使用されていることを前提としています

#foo.py
def some_fn():
    return 'some_fn'

class Foo(object):
    def method_1(self):
        return some_fn()

#bar.py
import foo
class Bar(object):
    def method_2(self):
        tmp = foo.Foo()
        return tmp.method_1()

#test_case_1.py
import bar
from mock import patch

@patch('foo.some_fn')
def test_bar(mock_some_fn):
    mock_some_fn.return_value = 'test-val-1'
    tmp = bar.Bar()
    assert tmp.method_2() == 'test-val-1'
    mock_some_fn.return_value = 'test-val-2'
    assert tmp.method_2() == 'test-val-2'

テストするモジュールを直接インポートする場合、次のようにpatch.objectを使用できます。

#test_case_2.py
import foo
from mock import patch

@patch.object(foo, 'some_fn')
def test_foo(test_some_fn):
    test_some_fn.return_value = 'test-val-1'
    tmp = foo.Foo()
    assert tmp.method_1() == 'test-val-1'
    test_some_fn.return_value = 'test-val-2'
    assert tmp.method_1() == 'test-val-2'

どちらの場合も、テスト関数が完了した後、some_fnは「非模擬」になります。

編集:複数の関数をモックするには、関数にデコレーターを追加し、引数を追加して追加のパラメーターを取得します

@patch.object(foo, 'some_fn')
@patch.object(foo, 'other_fn')
def test_foo(test_other_fn, test_some_fn):
    ...

デコレータが関数定義に近いほど、パラメータリスト内で早くなります。

80
Silfheed

これは、次のような方法で実行できます。

# foo.py
class Foo:
    def method_1():
        results = uses_some_other_method()


# testing.py
from mock import patch

@patch('Foo.uses_some_other_method', return_value="specific_value"):
def test_some_other_method(mock_some_other_method):
    foo = Foo()
    the_value = foo.method_1()
    assert the_value == "specific_value"

ここにあなたが読むことができるソースがあります: 間違った場所でのパッチング

13
chipz

あなたが話していることを明確にしましょう:外部メソッドuses_some_other_methodを呼び出すテストケースでFooをテストします。実際のメソッドを呼び出す代わりに、戻り値をモックする必要があります。

class Foo:
    def method_1():
       results = uses_some_other_method()
    def method_n():
       results = uses_some_other_method()

さて、上記のコードがfoo.pyにあり、uses_some_other_methodがモジュールbar.pyに定義されているとします。ユニットテストは次のとおりです。

import unitest
import mock

from foo import Foo


class TestFoo(unittest.TestCase):

    def setup(self):
        self.foo = Foo()

    @mock.patch('foo.uses_some_other_method')
    def test_method_1(self, mock_method):
        mock_method.return_value = 3
        self.foo.method_1(*args, **kwargs)

        mock_method.assert_called_with(*args, **kwargs)

異なる引数を渡すたびに戻り値を変更する場合、mockside_effect を提供します。

5
cizixs