当我无权访问实例本身时,如何设置模拟 class 实例的 return_value?
how do I set return_value of a mocked class instance when I don't have access to the instance itself?
假设我有一些函数 A.foo()
实例化并使用 B
的实例,调用它的成员函数 bar
。
当我测试我的 A
class 时,如何在 B
的模拟实例上设置 return_value
,因为我无权访问B
的实例?也许一些代码可以更好地说明这一点:
import unittest
import unittest.mock
import pandas
class A:
def foo(self):
b = B()
return b.bar()
class B:
def bar():
return 1
@unittest.mock.patch("__main__.B")
class MyTestCase(unittest.TestCase):
def test_case_1(self, MockB):
MockB.bar.return_value = 2
a = A()
self.assertEqual(a.foo(), 2)
test_case = MyTestCase()
test_case.test_case_1()
这失败了;
AssertionError: <MagicMock name='B().bar()' id='140542513129176'> != 2
显然 MockB.bar.return_value = 2
行没有修改方法的 return 值。
不用mock.patch
也能解决这个问题。更改 foo
方法以接受它应该构建的依赖项的工厂 (DI)。
class A:
def foo(self, b_factory: 'Callable[[], B]' = B):
b = b_factory()
return b.bar()
def normal_code():
a = A()
assert a.foo() == ...
def test():
dummy_b = ... # build a dummy object here however you like
a = A()
assert a.foo(b_factory=lambda: dummy_b) == 2
我认为你没有启动 MockB。可以直接mock "main.B.bar":
@unittest.mock.patch("__main__.B.bar")
class MyTestCase(unittest.TestCase):
def test_case_1(self, MockB):
MockB.return_value = 2
a = A()
self.assertEqual(a.foo(), 2)
您的代码中只有 1 个错误。替换此行:
MockB.bar.return_value = 2
收件人:
MockB.return_value.bar.return_value = 2
它会起作用。
我假设您粘贴的这段代码只是一个玩具示例。如果 class A
和 B
位于另一个文件中,例如src/somedir/somefile.py
,不要忘记修补完整路径。
@unittest.mock.patch("src.somedir.somefile.B")
class MyTestCase(unittest.TestCase):
...
更新
为了进一步展开,您可以在 docs:
中看到一些用法
>>> class Class:
... def method(self):
... pass
...
>>> with patch('__main__.Class') as MockClass:
... instance = MockClass.return_value
... instance.method.return_value = 'foo'
... assert Class() is instance
... assert Class().method() == 'foo'
...
所以在你的情况下:
MockB.bar.return_value
就像调用静态方法,例如print(MockB.bar())
MockB.return_value.bar.return_value
就像调用 class/instance 方法,例如print(MockB().bar())
形象化:
import unittest.mock
class SomeClass:
def method(self):
return 1
@unittest.mock.patch("__main__.SomeClass")
def test_mock(mock_class):
print(mock_class)
print(mock_class.return_value)
mock_class.method.return_value = -10
mock_class.return_value.method.return_value = -20
print(SomeClass.method())
print(SomeClass().method())
test_mock()
$ python3 test_src.py
<MagicMock name='SomeClass' id='140568144584128'>
<MagicMock name='SomeClass()' id='140568144785952'>
-10
-20
- 如您所见,
mock_class.return_value
是用于 SomeClass().method()
. 等实例操作的那个
假设我有一些函数 A.foo()
实例化并使用 B
的实例,调用它的成员函数 bar
。
当我测试我的 A
class 时,如何在 B
的模拟实例上设置 return_value
,因为我无权访问B
的实例?也许一些代码可以更好地说明这一点:
import unittest
import unittest.mock
import pandas
class A:
def foo(self):
b = B()
return b.bar()
class B:
def bar():
return 1
@unittest.mock.patch("__main__.B")
class MyTestCase(unittest.TestCase):
def test_case_1(self, MockB):
MockB.bar.return_value = 2
a = A()
self.assertEqual(a.foo(), 2)
test_case = MyTestCase()
test_case.test_case_1()
这失败了;
AssertionError: <MagicMock name='B().bar()' id='140542513129176'> != 2
显然 MockB.bar.return_value = 2
行没有修改方法的 return 值。
不用mock.patch
也能解决这个问题。更改 foo
方法以接受它应该构建的依赖项的工厂 (DI)。
class A:
def foo(self, b_factory: 'Callable[[], B]' = B):
b = b_factory()
return b.bar()
def normal_code():
a = A()
assert a.foo() == ...
def test():
dummy_b = ... # build a dummy object here however you like
a = A()
assert a.foo(b_factory=lambda: dummy_b) == 2
我认为你没有启动 MockB。可以直接mock "main.B.bar":
@unittest.mock.patch("__main__.B.bar")
class MyTestCase(unittest.TestCase):
def test_case_1(self, MockB):
MockB.return_value = 2
a = A()
self.assertEqual(a.foo(), 2)
您的代码中只有 1 个错误。替换此行:
MockB.bar.return_value = 2
收件人:
MockB.return_value.bar.return_value = 2
它会起作用。
我假设您粘贴的这段代码只是一个玩具示例。如果 class A
和 B
位于另一个文件中,例如src/somedir/somefile.py
,不要忘记修补完整路径。
@unittest.mock.patch("src.somedir.somefile.B")
class MyTestCase(unittest.TestCase):
...
更新
为了进一步展开,您可以在 docs:
中看到一些用法>>> class Class: ... def method(self): ... pass ... >>> with patch('__main__.Class') as MockClass: ... instance = MockClass.return_value ... instance.method.return_value = 'foo' ... assert Class() is instance ... assert Class().method() == 'foo' ...
所以在你的情况下:
MockB.bar.return_value
就像调用静态方法,例如print(MockB.bar())
MockB.return_value.bar.return_value
就像调用 class/instance 方法,例如print(MockB().bar())
形象化:
import unittest.mock
class SomeClass:
def method(self):
return 1
@unittest.mock.patch("__main__.SomeClass")
def test_mock(mock_class):
print(mock_class)
print(mock_class.return_value)
mock_class.method.return_value = -10
mock_class.return_value.method.return_value = -20
print(SomeClass.method())
print(SomeClass().method())
test_mock()
$ python3 test_src.py
<MagicMock name='SomeClass' id='140568144584128'>
<MagicMock name='SomeClass()' id='140568144785952'>
-10
-20
- 如您所见,
mock_class.return_value
是用于SomeClass().method()
. 等实例操作的那个