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

FastAPI中如何用Pytest测试依赖MongoEngine的函数?Mock失败求助

问题

我有一个基于MongoDB的FastAPI项目,需要为依赖Mongo连接的函数编写测试。以下是我的users集合模型:

from mongoengine import Document, EmailField, StringField, EnumField 
class User(Document):  
    meta = {"collection": "users"}
    email = EmailField(unique=True)
    hashed_password = StringField()
    role = EnumField(UserRole)

    def username(self):
        return self.email.split('@')[0]

    def __str__(self):
        return f'{self.email} ({self.role})'

待测试的UserService函数如下:

class UserService:

    @staticmethod
    def existing_user(email: str) -> Optional[User]:
        try:
             user = User.objects(email=email).first()
        except ServerSelectionTimeoutError as e:
            raise e

        return user

我希望用Pytest测试该函数,尝试通过mongomock或monkeypatch模拟MongoDB但未成功,我的测试代码如下:

from domain.entities.user import UserRole, User
from mongomock import MongoClient
class TestUserServiceMethods:

    email="john@doe.fr"

    # User example
    user = User(email=email,
                  role=UserRole.admin,
                  hashed_password="hashed_pwd")

    add_user = {
      "email": email,
      "role": UserRole.admin,
      "hashed_password": "hashed_pwd"
    }

    user_service = UserService()

    client = MongoClient()

    mock_db = client['ml-db']
    user_collection = mock_db['users']
    user_collection.insert_one(add_user)

    def test_existing_user(self, monkeypatch):
        with monkeypatch.context() as m:
            m.setattr('pymongo.MongoClient', lambda *args, **kwargs: self.client)

            result = self.user_service.existing_user(self.email)

             assert result == self.user

运行测试时出现错误:

mongoengine.connection.ConnectionFailure: You have not defined a default connection

请问测试该函数的最佳方式是什么?是否应该直接使用FastAPI的test_client?

解决方案

失败原因

你用monkeypatch替换pymongo.MongoClient的方式不适用于mongoengine——mongoengine有独立的连接管理机制,不会直接调用pymongo.MongoClient初始化连接,而是通过mongoengine.connect()或配置建立默认连接,因此才会触发“未定义默认连接”的错误。

正确测试方案(mongomock + mongoengine)

无需使用monkeypatch,直接让mongoengine连接到mongomock实例即可,代码示例如下:

from domain.entities.user import UserRole, User
from mongomock import MongoClient
from mongoengine import connect, disconnect
import pytest
from your_module import UserService  # 替换为UserService实际所在模块路径

class TestUserServiceMethods:
    email = "john@doe.fr"
    test_user_data = {
        "email": email,
        "role": UserRole.admin,
        "hashed_password": "hashed_pwd"
    }

    @classmethod
    def setup_class(cls):
        # 连接到mongomock数据库
        cls.client = MongoClient()
        connect(
            db='ml-db',
            host='mongodb://localhost',
            client=cls.client
        )
        # 创建测试用户
        User(**cls.test_user_data).save()

    @classmethod
    def teardown_class(cls):
        # 断开连接并清理测试数据
        disconnect()
        cls.client.drop_database('ml-db')

    def test_existing_user(self):
        result = UserService.existing_user(self.email)
        assert result is not None
        assert result.email == self.email
        assert result.role == UserRole.admin

是否需要使用FastAPI的TestClient?

取决于测试目标:

  • 若仅测试UserService.existing_user这类独立业务逻辑函数,不需要用TestClient,直接测试函数本身更高效。
  • 若要验证完整API链路(从HTTP请求到数据库查询的全流程),则需要用TestClient模拟请求,校验接口返回结果。

额外注意事项

  • 用setup_class/teardown_class或pytest fixture管理连接与测试数据,确保每个用例的环境独立干净。
  • 避免在类级别直接创建User实例,需等mongoengine连接建立后再初始化测试数据。

内容的提问来源于stack exchange,提问作者Rickross

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 22:54:53