如何在Pytest中Mock Python函数的MongoDB URI配置调用?
问题场景
我正在为get_indexes函数编写Pytest测试,该函数通过import_configuration("mongodb", "uri")获取MongoDB URI并创建MongoClient连接db_data库。我已经用mongomock编写了数据库fixture,但不知道如何Mock函数中创建MongoClient的逻辑,让函数直接使用fixture中的db_data实例,而非读取配置文件的URI。
目标函数代码
def get_indexes(collection, database, criterias): file = database.files.find_one( {"_id": bson.ObjectId(collection)}, {"_id": 0, "internal_name": 1})["internal_name"] server = MongoClient(import_configuration("mongodb", "uri")) database_data = server["db_data"] indexes = database_data[file].index_information() fields_names = [] for criteria in criterias: field = database.champs.find_one( {"_id": criteria["field"]}, {"_id": 0, "internal_name": 1})["internal_name"] fields_names.append(field) names_joined = "" for field in fields_names: names_joined += f"{field}_1" if names_joined in indexes: return True return False
现有测试fixture代码
@pytest.fixture(scope='session') def database(): client = mongomock.MongoClient("mongodb://127.0.0.1:27016/") db = client.db db_data = client.db_data # Files objects = [ { "_id": ObjectId("65afa95dbd2214f7afa80aa6"), "internal_name": "test", "name": "toto", "percent_s": 80, "percent_m": 50 }, { "_id": ObjectId("65afa95dbd2214f7afa80aa7"), "internal_name": "test2", "name": "titi", "percent_s": 45, "percent_m": 12 }, ] db.files.insert_many(objects) # 修正原fixture拼写错误:匹配函数中的database.files # Champs objects = [ { "_id": ObjectId("65afa95dbd2214f7afa80aa8"), "internal_name": "name" }, { "_id": ObjectId("65afa95dbd2214f7afa80aa9"), "internal_name": "test2" }, ] db.champs.insert_many(objects) # 修正原fixture拼写错误:匹配函数中的database.champs # db_data初始化 file = db.files.find_one({"_id": ObjectId("65afa95dbd2214f7afa80aa6")}, {"_id": 0, "internal_name": 1})["internal_name"] objects = [ { "_id": "idindividu01", "_idhouse": "idfoyer01", "index": "index" }, { "_id": "idindividu02", "_idhouse": "idfoyer02", "index": "index" } ] db_data[file].insert_many(objects) collection = db_data[file] collection.create_index([("index", ASCENDING)], background=False) return db, db_data
解决方案
通过Mock函数中的MongoClient类,让它返回fixture中已初始化的mongomock客户端,跳过读取配置文件创建新连接的逻辑,直接复用fixture中的db_data实例。
修改后的测试函数
from pytest_mock import MockerFixture from bson import ObjectId @pytest.mark.parametrize( "collection,criterias,expected", [ # 修正测试用例键名:匹配函数中的criteria["field"] (ObjectId("65afa95dbd2214f7afa80aa6"), [{"field": ObjectId("65afa95dbd2214f7afa80aa8")}, {"field": ObjectId("65afa95dbd2214f7afa80aa9")}], False), ], ) def test_get_indexes(collection, criterias, expected, database, mocker: MockerFixture): # 从fixture中获取db_data实例及对应客户端 _, db_data = database # 替换"your_module"为get_indexes函数所在的模块名(例如src.data_utils) mock_mongo_client = mocker.patch("your_module.MongoClient") # 让Mock的MongoClient返回fixture中的mongomock客户端 mock_mongo_client.return_value = db_data.client # 执行测试并断言结果 value = get_indexes(collection, database[0], criterias) assert value == expected
关键说明
- Mock路径正确性:必须使用
get_indexes函数所在模块中导入的MongoClient路径,而非直接pymongo.MongoClient,因为Python Mock基于模块命名空间生效。 - 修正代码不一致:原fixture和测试用例中存在拼写/键名错误,需统一匹配函数中的字段名才能保证测试正常运行。
- 复用fixture资源:通过
db_data.client直接获取fixture中创建的客户端实例,确保函数使用的数据库与测试初始化的完全一致。
内容的提问来源于stack exchange,提问作者Morgane FLAMANT
相关产品推荐
相关产品推荐

