OK、
これは manual で言及されていることを知っており、おそらくside_effect
やreturn_value
と関係があるはずですが、簡単で直接的な例が役立ちます非常に。
私が持っています:
class ClassToPatch():
def __init__(self, *args):
_do_some_init_stuff()
def some_func():
_do_stuff()
class UUT():
def __init__(self, *args)
resource_1 = ClassToPatch()
resource_2 = ClassToPatch()
ここで、UUT
クラスを単体テストし、ClassToPatch
をモックしたいと思います。 UUT
クラスが2つのClassToPatch
オブジェクトをインスタンス化することを知っているので、Mockフレームワークがインスタンス化ごとに新しいMockオブジェクトを返すようにしたいので、後でそれぞれ個別に呼び出しをアサートできます。
テストケースで@patch
デコレータを使用してこれを実現するにはどうすればよいですか?つまり、次のコードサンプルを修正するにはどうすればよいですか?
class TestCase1(unittest.TestCase):
@patch('classToPatch.ClassToPatch',autospec=True)
def test_1(self,mock1,mock2):
_assert_stuff()
ここにあなたを始めるための簡単な例があります:
import mock
import unittest
class ClassToPatch():
def __init__(self, *args):
pass
def some_func(self):
return id(self)
class UUT():
def __init__(self, *args):
resource_1 = ClassToPatch()
resource_2 = ClassToPatch()
self.test_property = (resource_1.some_func(), resource_2.some_func())
class TestCase1(unittest.TestCase):
@mock.patch('__main__.ClassToPatch', autospec = True)
def test_1(self, mock1):
ctpMocks = [mock.Mock(), mock.Mock()]
ctpMocks[0].some_func.return_value = "funky"
ctpMocks[1].some_func.return_value = "monkey"
mock1.side_effect = ctpMocks
u = UUT()
self.assertEqual(u.test_property, ("funky", "monkey"))
if __name__ == '__main__':
unittest.main()
私は追加しました test_property
をUUTに追加して、単体テストで有用な処理を行う今、モックなしtest_property
は、2つのClassToPatch
インスタンスのIDを含むタプルである必要があります。しかし、モックではタプルになるはずです:("funky", "monkey")
。
side_effect
モックオブジェクトのプロパティ。これにより、ClassToPatch
イニシャライザーの各呼び出しでUUT
の異なるインスタンスが返されます。
お役に立てれば。
編集:ところで、ユニットテストを実行すると、次のようになります。
.
----------------------------------------------------------------------
Ran 1 test in 0.004s
OK
これは、作成された任意の数のインスタンスを処理するためのより一般的な別のバージョンです。
class TestUUT:
def test_init(self, mocker):
class MockedClassToPatchMeta(type):
static_instance = mocker.MagicMock(spec=ClassToPatch)
def __getattr__(cls, key):
return MockedClassToPatchMeta.static_instance.__getattr__(key)
class MockedClassToPatch(metaclass=MockedClassToPatchMeta):
original_cls = ClassToPatch
instances = []
def __new__(cls, *args, **kwargs):
MockedClassToPatch.instances.append(
mocker.MagicMock(spec=MockedClassToPatch.original_cls))
MockedClassToPatch.instances[-1].__class__ = MockedClassToPatch
return MockedClassToPatch.instances[-1]
mocker.patch(__name__ + '.ClassToPatch', new=MockedClassToPatch)
UUT()
# since your original code created two instances
assert 2 == len(MockedClassToPatch.instances)
各インスタンスに対してより完全な検証が必要な場合は、MockedClassToPatch.instances[0]
またはMockedClassToPatch.instances[1]
にアクセスできます。
また、メタクラスのボイラープレートを生成するために ヘルパーライブラリ を作成しました。私が書いたあなたの例に必要なコードを生成するために:
print(PytestMocker(mocked=ClassToPatch, name=__name__).mock_classes().mock_classes_static().generate())