模拟在 with 语句中使用的 class
Mocking a class used in a with statement
我有一个 class,它有一个 __exit__
和 __enter__
函数,这样我就可以在 with 语句中使用它,例如:
with ClassName() as c:
c.do_something()
我现在正在尝试编写一个单元测试来对此进行测试。基本上,我试图测试 do_something()
只被调用过一次。
一个例子(我称之为testmocking1
):
class temp:
def __init__(self):
pass
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def test_method(self):
return 1
def fun():
with temp() as t:
return t.test_method()
还有我的测试:
import unittest
import test_mocking1
from test_mocking1 import fun
import mock
from mock import patch
class MyTestCase(unittest.TestCase):
@patch('test_mocking1.temp', autospec = True)
def test_fun_enter_called_once(self, mocked_object):
fun()
mocked_object.test_method.assert_called_once()
if __name__ == '__main__':
unittest.main()
所以我希望这会通过,因为 test_method 在函数 fun()
中只被调用了一次。但我得到的实际结果是:
======================================================================
FAIL: test_fun_enter_called_once (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<path_to_virtual_env>\lib\site-packages\mock\mock.py", line 1305, in patched
return func(*args, **keywargs)
File "<File_with_test>", line 11, in test_fun_enter_called_once
mocked_object.test_method.assert_called_once()
File "<path_to_virtual_env>\lib\site-
packages\mock\mock.py", line 915, in assert_called_once
raise AssertionError(msg)
AssertionError: Expected 'test_method' to have been called once. Called 0 times.
如何测试使用 with
语句创建的 class 中的函数是否已被调用(一次或多次),以及(相关)如何设置这些调用的结果(使用 .side_effect
或 .return_value
)?
with
语句采用任何 __enter__
return 绑定到 as <name>
部分中的名称。您将其绑定到 t
:
with temp() as t:
t.test_method()
注意调用了temp()
,所以with
语句以temp.return_value
开头。 t
也不是 temp.return_value
,它是任何 temp().__enter__()
returns,因此您需要为该调用使用 return 值:
entered = mocked_object.return_value.__enter__.return_value
entered.test_method.assert_called_once()
对此进行扩展,如果您想更改 test_method()
return 的内容,请对 mocked_object.return_value.__enter__.return_value
的 return 值进行更改。
您可以随时打印出对象的 mock_calls()
attribute 以查看它发生了什么:
>>> from test_mocking1 import fun
>>> from mock import patch
>>> with patch('test_mocking1.temp', autospec = True) as mocked_object:
... fun()
...
>>> print(mocked_object.mock_calls)
[call(),
call().__enter__(),
call().__enter__().test_method(),
call().__exit__(None, None, None)]
>>> mocked_object.return_value.__enter__.return_value.test_method.called
True
>>> mocked_object.return_value.__enter__.return_value.test_method.call_count
1
请注意,您 temp.__enter__()
returns None
的实际实现,因此如果不模拟您的 fun()
函数,则会因属性错误而失败。
我有一个 class,它有一个 __exit__
和 __enter__
函数,这样我就可以在 with 语句中使用它,例如:
with ClassName() as c:
c.do_something()
我现在正在尝试编写一个单元测试来对此进行测试。基本上,我试图测试 do_something()
只被调用过一次。
一个例子(我称之为testmocking1
):
class temp:
def __init__(self):
pass
def __enter__(self):
pass
def __exit__(self, exc_type, exc_val, exc_tb):
pass
def test_method(self):
return 1
def fun():
with temp() as t:
return t.test_method()
还有我的测试:
import unittest
import test_mocking1
from test_mocking1 import fun
import mock
from mock import patch
class MyTestCase(unittest.TestCase):
@patch('test_mocking1.temp', autospec = True)
def test_fun_enter_called_once(self, mocked_object):
fun()
mocked_object.test_method.assert_called_once()
if __name__ == '__main__':
unittest.main()
所以我希望这会通过,因为 test_method 在函数 fun()
中只被调用了一次。但我得到的实际结果是:
======================================================================
FAIL: test_fun_enter_called_once (__main__.MyTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "<path_to_virtual_env>\lib\site-packages\mock\mock.py", line 1305, in patched
return func(*args, **keywargs)
File "<File_with_test>", line 11, in test_fun_enter_called_once
mocked_object.test_method.assert_called_once()
File "<path_to_virtual_env>\lib\site-
packages\mock\mock.py", line 915, in assert_called_once
raise AssertionError(msg)
AssertionError: Expected 'test_method' to have been called once. Called 0 times.
如何测试使用 with
语句创建的 class 中的函数是否已被调用(一次或多次),以及(相关)如何设置这些调用的结果(使用 .side_effect
或 .return_value
)?
with
语句采用任何 __enter__
return 绑定到 as <name>
部分中的名称。您将其绑定到 t
:
with temp() as t:
t.test_method()
注意调用了temp()
,所以with
语句以temp.return_value
开头。 t
也不是 temp.return_value
,它是任何 temp().__enter__()
returns,因此您需要为该调用使用 return 值:
entered = mocked_object.return_value.__enter__.return_value
entered.test_method.assert_called_once()
对此进行扩展,如果您想更改 test_method()
return 的内容,请对 mocked_object.return_value.__enter__.return_value
的 return 值进行更改。
您可以随时打印出对象的 mock_calls()
attribute 以查看它发生了什么:
>>> from test_mocking1 import fun
>>> from mock import patch
>>> with patch('test_mocking1.temp', autospec = True) as mocked_object:
... fun()
...
>>> print(mocked_object.mock_calls)
[call(),
call().__enter__(),
call().__enter__().test_method(),
call().__exit__(None, None, None)]
>>> mocked_object.return_value.__enter__.return_value.test_method.called
True
>>> mocked_object.return_value.__enter__.return_value.test_method.call_count
1
请注意,您 temp.__enter__()
returns None
的实际实现,因此如果不模拟您的 fun()
函数,则会因属性错误而失败。