我正在尝试使用MagicMock编写单元测试。
我有两个正在测试的类:
class HelperClass:
@property
def output(self) -> dict[str, Any]:
return self._output
def __enter__(self):
print("__enter__")
self._output: dict[str, Any] = {}
return self
def __exit__(self, exc_type, exc_value, exc_traceback):
print("__exit__")
class ImportantClass:
def fn(self, key: str):
with self._fac() as hc:
if key not in hc.output:
raise RuntimeError("bad bad not good")
return hc.output[key]
def __init__(self, fac: Callable[[], HelperClass]):
self._fac = fac
ImportantClass
是用一个工厂方法初始化的,这个工厂方法可以用来创建HelperClass
的实例。下面是测试代码
def test_important_class():
hc = MagicMock(spec=HelperClass)
omock = PropertyMock(return_value={"foo": "bar", "baz": "quux"})
type(hc).output = omock
assert hc.output["foo"] == "bar"
assert hc.output["baz"] == "quux" # these assertions succeed
assert OuterClass(fac=lambda: hc).fn("foo") == "bar"
assert OuterClass(fac=lambda: hc).fn("baz") == "quux" # these don't
当我在调试器中运行代码时,hc.output
的类型在测试中是dict[str: str]
,但当我进入fn
方法时,hc.output
的类型是MagicMock
。
更新我发现了这个问题,这表明我所面临的问题与调用with self._fac() as hc
时正在创建的隐式ContextManager
有关。
我仍然有一个艰难的时间更新测试,使ContextManager
得到适当的嘲笑。
最后,我必须创建一个可以在单元测试中修补的方法
def get_mtc(self) -> MyTestClass: # this is a dummy method that will get patched
return MyTestClass()
def test_test_class():
patcher = patch("my_unit_tests.get_mtc")
fty = patcher.start()
fty.return_value.__enter__.return_value.output = {"foo": "bar", "baz": "quux"} # mocks the implicit ContextManager
assert OuterClass(fty).fn("foo") == "bar"
assert OuterClass(fty).fn("baz") == "quux"
patcher.stop()
我非常有兴趣学习一种更python化的方法来完成所有这些。