![](/img/trans.png)
[英]Unittest for context-manager fails with AttributeError: __exit__
[英]Mock for context-manager fails with AttributeError: __exit__
我正在嘗試使用Mock修補一些上下文管理器功能,因此我可以測試代碼在給出好,壞和垃圾輸入的情況下做出明智的事情。 這是帶有with
語句的測試代碼。 補丁在我的代碼中的正確位置完成。
@patch("__main__.opened_w_error")
def test_get_recipe_file(self, mo):
mo.return_value = (Mock(), None)
mo.__enter__ = Mock(return_value=None)
mo.__exit__ = Mock(return_value=None)
with mo(…) as (fd, err): # AttributeError: __exit__ is raised here.
print(fd)
print(err)
但是, with mo(…) as (fd, err)
會引發AttributeError: __exit__
。
with mo as (fd, err):
…
后一段代碼是我試圖嘲笑的。 但這不是我在代碼中使用它的方式。 對於那些真正感興趣的人,我試圖在PEP 343中模擬示例6的opened_w_error()
來處理打開文件和捕獲錯誤。 因此代碼是:
with open_w_error(filename, 'r') as (fd, err):
…
后者是我想要嘲笑的。
請注意,您傳遞到with語句的對象是,應該有一個__enter__
和__exit__
方法,從返回值__enter__
用於as
結構。 在你的情況下,你正在調用mo(...)
,它返回(Mock(), None)
,這不是一個上下文管理器。 您應該將此返回值移動到__enter__
方法。
@patch("__main__.opened_w_error")
def test_get_recipe_file(self, mo):
mo.__enter__ = Mock(return_value=(Mock(), None))
mo.__exit__ = Mock(return_value=None)
with mo as (fd, err):
print(fd)
print(err)
編輯 :如果您仍想調用mo
,則將其返回值設為上下文管理器。
@patch("__main__.opened_w_error")
def test_get_recipe_file(self, m_opened_w_error):
mo = Mock()
mo.__enter__ = Mock(return_value=(Mock(), None))
mo.__exit__ = Mock(return_value=None)
m_opened_w_error.return_value = mo
with m_opened_w_error(...) as (fd, err):
print(fd)
print(err)
問題是當你調用mo(..)
它返回的對象( tuple
)沒有__enter__
和__exit__
屬性。
為了解決這個問題分配mo
來mo
的return_value
使上下文管理屬性你就可以設置仍然可以發現。
@patch("__main__.opened_w_error")
def test_get_recipe_file(self, mo):
mo.return_value = mo
mo.__enter__ = Mock(return_value=(Mock(), None))
mo.__exit__ = Mock(return_value=None)
with mo('file', 'r') as (fd, err):
print(fd)
print(err)
mo.assert_called_once_with('file', 'r') # Should be True
你需要的是這個:
with mock.patch('__main__.opened_w_error') as mo:
mo.__enter__ = Mock(return_value=(Mock(), None))
mo.__exit__ = Mock(return_value=None)
# Your code goes here
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.