如何正确Mock NamedTemporaryFile的write、close方法解决单元测试报错
问题解答
报错原因确认
是的,该报错确实是你对NamedTemporaryFile的Mock配置不正确导致的,主要有两处配置错误:
- 你直接将
NamedTemporaryFile的返回值设为None,但with语句要求NamedTemporaryFile()返回的对象必须是上下文管理器,要实现__enter__、__exit__方法才能正常执行上下文逻辑 - 你没有给上下文管理器返回的
temp对象配置对应的write方法、close方法和name属性,导致后续调用temp.write、读取temp.name时行为完全不符合预期
正确的测试实现
你可以按照下面的方式配置Mock,即可完成测试:
from unittest.mock import patch, Mock, mock_open # 注意patch的执行顺序是从下往上,所以参数顺序要反过来 @patch.object(tempfile, "NamedTemporaryFile") @patch("builtins.open", new_callable=mock_open, read_data=b"test pdf content") def test_submit_form(self, mock_open_inst, mock_named_temp_file): # 1. 构造模拟的临时文件对象 mock_temp = Mock() # 配置临时文件对象的必备属性和方法 mock_temp.name = "mock_temp_file.pdf" mock_temp.write = Mock() mock_temp.close = Mock() # 2. 配置NamedTemporaryFile的上下文管理器行为 # with语句会调用返回对象的__enter__方法,将返回值赋值给temp变量 mock_named_temp_file.return_value.__enter__.return_value = mock_temp # 3. 可选:模拟Google Cloud Storage的上传方法,验证上传逻辑 mock_gcs = Mock() mock_gcs.upload_file.return_value = "gcs_stored_path.pdf" self._payment_approval_service._google_cloud_storage = mock_gcs # 4. 构造测试参数并执行测试 test_pdf_bytes = b"test pdf content bytes" test_input_path = "testfilepath.pdf" result_path = self._payment_approval_service.submit_form(test_pdf_bytes, test_input_path) # 5. 验证逻辑正确性(可选但推荐) # 验证临时文件写入了正确的字节内容 mock_temp.write.assert_called_once_with(test_pdf_bytes) # 验证临时文件被正常关闭 mock_temp.close.assert_called_once() # 验证open方法读取了正确的临时文件 mock_open_inst.assert_called_once_with("mock_temp_file.pdf", "rb") # 验证GCS上传方法被正常调用 mock_gcs.upload_file.assert_called_once()
额外说明
你的业务代码中使用with语句管理NamedTemporaryFile生命周期的情况下,本身不需要手动调用temp.close(),with语句退出时会自动执行关闭逻辑,不过这部分不影响测试结果。
内容的提问来源于stack exchange,提问作者Faris Dewantoro
相关产品推荐
相关产品推荐

