You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 11:43:15