Mock数据库游标上下文管理器缺失__enter__致测试报错求助
问题分析与解决
常见原因及对应解法
1. PropertyMock 未正确指向具备上下文能力的游标对象
确保你通过 PropertyMock 返回的 mock 游标对象本身实现了上下文管理器协议(即拥有 __enter__ 和 __exit__ 方法)。
比如你的 mock_db fixture 应该这样定义:
import pytest from unittest.mock import Mock @pytest.fixture def mock_db(): # 模拟游标对象,实现上下文管理器 mock_cursor = Mock() # __enter__ 返回游标自身(对应 with 语句的 as 变量) mock_cursor.__enter__.return_value = mock_cursor # __exit__ 正常返回 None(不抑制异常) mock_cursor.__exit__.return_value = None mock_cursor.execute.return_value = None # 模拟数据库连接对象,cursor 属性返回上面的 mock_cursor mock_conn = Mock() mock_conn.cursor = mock_cursor return mock_conn
然后在测试用例中,用 PropertyMock 替换 Importer 的 cursor 属性时,直接返回 mock_db.cursor:
from unittest.mock import PropertyMock def test_drop_import_table(monkeypatch, mock_db): # 替换 Importer 的 cursor 属性为 mock 的游标 monkeypatch.setattr(Importer, "cursor", PropertyMock(return_value=mock_db.cursor)) importer = Importer() importer.drop_import_table() # 验证 execute 被正确调用 mock_db.cursor.execute.assert_called_once_with("DROP TABLE IF EXISTS import_table")
2. 误将游标模拟为方法而非属性
如果你的 Importer 类中 cursor 是 属性(比如用 @property 装饰),但你在 mock 时错误地让它返回一个方法,就会导致 with self.cursor as c 报错——因为此时 self.cursor 是一个未调用的方法,不是上下文管理器对象。
检查你的 mock 代码,确保 PropertyMock 的 return_value 是一个直接可用的游标对象,而不是需要调用的方法。
3. 游标对象的上下文方法未正确绑定
如果你的 mock_cursor 是通过其他方式创建的(比如手动模拟类而非使用 Mock),要确保 __enter__ 和 __exit__ 是绑定到对象的方法,而不是未绑定的函数。使用 unittest.mock.Mock 会自动处理方法绑定,所以优先用 Mock 类来创建模拟对象。
4. 代码中 self.cursor 的实际行为与预期不符
检查 Importer 类的 cursor 属性实现:
- 确认它是直接返回游标对象,还是返回一个创建游标的方法?
- 如果是后者(比如
self.cursor()才会得到游标),那你的测试代码需要调整——此时with self.cursor() as c才是正确的,而你的 mock 应该让cursor方法返回具备上下文能力的对象。
比如如果 Importer 的 cursor 是方法:
class Importer: def cursor(self): # 返回数据库游标 return self.db.cursor()
那测试时应该 mock 这个方法,而不是用 PropertyMock:
def test_drop_import_table(monkeypatch, mock_db): monkeypatch.setattr(Importer, "cursor", Mock(return_value=mock_db.cursor)) importer = Importer() importer.drop_import_table()
内容的提问来源于stack exchange,提问作者Keith Lee
相关产品推荐
相关产品推荐

