3

Python 3 モック オブジェクトは、呼び出しに対する引数のクエリをサポートしていますが、呼び出しによって返される値をクエリすることもできますか?

私の特定のシナリオは、tempfile.mkdtemp をモックすることですが、副作用として実際の mkdtemp を呼び出します。テストで作成された一時ディレクトリを取得したいと思います。

from unittest import mock
import shutil
import tempfile

from app import production_function


def mkdtemp(*args, **kwargs):
    dtemp = orig_mkdtemp(*args, **kwargs)
    return dtemp


orig_mkdtemp = tempfile.mkdtemp
patcher = mock.patch('tempfile.mkdtemp', name='tempfile.mkdtemp')
the_mock = patcher.start()
the_mock.side_effect = mkdtemp

# Call function under test
production_function()

assert the_mock.called
# Now, how to get the return value from the call to the_mock?

patcher.stop()
4

2 に答える 2

2

残念ながら、mockモジュールは戻り値を保存しません (debugguer で確認しましたが、その痕跡はありません)。の値を返す前に保存する必要がありますside_effect

オブジェクトを使用して、汚れた作業を処理できます。たとえば、非常に基本的な実装は次のようになります。

class SideEffect():
    def __init__(self, n):
        self.values = iter(range(n))
        self.return_value = None

    def __call__(self):
        self.return_value = next(self.values)
        return self.return_value


a = Mock()
se = SideEffect(10)
a.side_effect = se

for x in range(10):
    v = a()
    assert v == se.return_value
    print("a()={}  return_value={}".format(v, se.return_value))

side_effect関数をラップし、引数と例外を処理するより洗練されたものが必要な場合、例は次のようになります。

class GenericSideEffect():
    def __init__(self, f, *args, **kwargs):
        self.v_function = f
        self.args = args
        self.kwargs = kwargs
        self._return_value = Exception("Never Called")

    def __call__(self):
        try:
            self._return_value = self.v_function(*self.args, **self.kwargs)
            return self._return_value
        except Exception as e:
            self.return_value = e
            raise e

    @property
    def return_value(self):
        if isinstance(self._return_value, Exception):
            raise self._return_value
        return self._return_value

もちろんデコレータとして書いて署名を保存することもできますが、その部分はその回答の範囲外だと思います。

于 2014-11-02T15:15:05.643 に答える
1

コンポートメントが決定論的であり、状態が少ない場合は、モックに対して行われた呼び出しのリストを取得し、関心のあるネストされた呼び出しを再度呼び出して結果をキャッチできます。そうでなければ、次のようなことができると思います:

def mkdtemp_wrapper(result_storage):
    def mkdtemp(*args, **kwargs):
        dtemp = orig_mkdtemp(*args, **kwargs)
        result_storage.append(((*args,**kwargs),dtemp))
        return dtemp
    return mkdtemp

モックを次のように変更します。

results_values = []
the_mocks.side_effect = mkdtemp_wrapper(result_values)

そして、結果の値には、いくつかの引数のリスト、results があります。

それが役に立てば幸い。

于 2014-10-31T10:26:46.957 に答える