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
相关产品推荐
相关产品推荐

