如何正确Mock FastAPI端点处理器内的函数?
FastAPI端点函数Mock失效问题解决
问题描述
在测试FastAPI接收文件的端点时,需要Mock封装了S3上传逻辑的s3_upload函数,但使用TestClient调用端点时Mock始终不生效,程序仍会尝试真实上传S3。直接调用处理器函数时Mock正常,推测和FastAPI调用机制有关。
相关代码示例:
# a_module/s3_upload.py def s3_upload(bucket, filename, file): client = boto3.client('s3') client.put_object(Bucket="a-bucket", Key=filename, body=file)
# endpoints/route_file.py from a_module import s3_upload @app.put("/") def route_file(file, filename): check_valid_file() s3_upload() @pytest.fixture def client(): yield TestClient(app)
# tests/test_routes.py def test_route_file(client, mocker): test_file = <whatever> mocker.patch("endpoints.s3_upload") response = client.put("/", file=test_file)
核心原因与解决办法
问题根源是Mock路径错误,Python的unittest.mock(包括pytest-mocker)遵循"where it's used"原则:必须patch函数被实际调用的模块中的引用,而非函数定义的模块路径。
在route_file.py中,你通过from a_module import s3_upload将函数导入到了endpoints.route_file模块的命名空间下,端点函数调用的是这个本地引用。而你当前patch的endpoints.s3_upload是错误路径(该路径不存在)。
修正步骤:
- 把patch路径改为
endpoints.route_file.s3_upload - 可选:添加Mock调用验证,确保Mock生效
修正后的测试代码:
# tests/test_routes.py def test_route_file(client, mocker): test_file = <whatever> # 修正patch路径为函数被调用的模块路径 mock_upload = mocker.patch("endpoints.route_file.s3_upload") response = client.put("/", file=test_file) # 验证Mock是否被正确调用 mock_upload.assert_called_once()
额外说明:如果你的端点函数是通过import a_module然后调用a_module.s3_upload(),那么需要patch的路径就是a_module.s3_upload,此时直接patch原模块的函数即可。
内容的提问来源于stack exchange,提问作者BlindPrimate
相关产品推荐
相关产品推荐

