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

SQLAlchemy 2.0测试Mock失效致数据入库,求解决方案

解决SQLAlchemy仓库测试时写入真实数据库的问题

测试SQLAlchemy 2.0仓库时碰到唯一约束冲突错误:

sqlalchemy.exc.IntegrityError: (psycopg2.errors.UniqueViolation) duplicate key value violates unique constraint "professions_name_key"

明明用了pytest-mock做Mock测试,但数据还是被写入真实数据库,怎么避免?


问题根源

你当前的Mock策略不对:

  1. 仓库代码里是通过session = Session()创建Session实例来操作数据库,但你只Mock了Session类的add/commit/refresh方法,这不会影响真实的Session实例创建和执行。
  2. 你Mock的ProfessionsDBModel是类本身,但仓库里是创建这个类的实例,断言时传类对象也不符合实际逻辑。

解决方案

要彻底隔离真实数据库,核心是让仓库拿到的Session是一个Mock实例,所有数据库操作都走这个Mock,不碰真实库。具体调整如下:

修正后的测试代码

import uuid
import pytest
from src.domain.entities.profession import Profession
from src.infra.repositories.profession_postgresql_repository import ProfessionPostgresqlRepository


def test_profession_postgresql_repository(mocker, fixture_profession_developer):
    # Mock uuid生成逻辑
    mocker.patch(
        'uuid.uuid4',
        return_value=fixture_profession_developer["profession_id"]
    )
    
    # 1. Mock仓库中使用的Session类,让它返回一个Mock实例
    mock_session = mocker.Mock()
    mocker.patch(
        'src.infra.repositories.profession_postgresql_repository.Session',
        return_value=mock_session
    )
    
    # 2. Mock ProfessionsDBModel类,捕获实例化后的对象
    mock_profession_db_cls = mocker.patch(
        'src.infra.repositories.profession_postgresql_repository.ProfessionsDBModel'
    )

    # 执行仓库方法
    repository = ProfessionPostgresqlRepository()
    result = repository.create(
        fixture_profession_developer["name"],
        fixture_profession_developer["description"]
    )

    # 3. 断言Session实例的方法被正确调用
    mock_session.add.assert_called_once_with(mock_profession_db_cls.return_value)
    mock_session.commit.assert_called_once()
    mock_session.refresh.assert_called_once_with(mock_profession_db_cls.return_value)
    
    # 可选:断言转换后的实体是否符合预期
    assert result.profession_id == fixture_profession_developer["profession_id"]
    assert result.name == fixture_profession_developer["name"]

关键改动说明

  • Mock正确的Session路径:Python的Mock基于导入路径生效,仓库里是从db_base导入Session到自身模块,所以必须在仓库模块的路径下MockSession,才能覆盖真实的导入。
  • 用Mock实例替代真实Session:让Session()返回一个Mock对象,这样仓库里的session.add/commit/refresh都是调用这个Mock实例的方法,不会触发真实数据库操作。
  • 修正断言逻辑:用assert_called_once_with做方法调用断言,并且传入mock_profession_db_cls.return_value(即类实例化后的对象),符合仓库代码的实际执行逻辑。

内容的提问来源于stack exchange,提问作者Claudio Shigueo Watanabe

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 02:16:32