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

使用create_app工厂模式的Flask+pytest测试出现404错误排查

问题:Flask测试环境使用自定义配置时接口返回404

我正在开发基于客户端-服务器架构的小型Flask应用,在通过pytest配置测试环境以使用预设数据库时遇到问题。项目结构如下:

|   config.py
|   Pipfile
|                
+---client
+---mobile_app
+---server
|   |   database.py
|   |   server.py
|           
+---tests
|   |   test_database.py
|   |   test_server.py
|   |   __init__.py

server.py 内容:

from flask import Flask
from flask_restful import Api, Resource

def create_app(config_obj):
    app = Flask(__name__)
    app.config.from_object(config_obj)
    return app

app = create_app('config.DefaultConfig')
api = Api(app)

class Balance(Resource):
    @staticmethod
    def get(user_id):
        balance = 0 * user_id
        return {"balance": balance}

api.add_resource(Balance, "/<int:user_id>/balance")

if __name__ == "__main__":
    app.run(debug=True)

config.py 内容:

class DefaultConfig:
    DEBUG = True
    TESTING = False
    PROPAGATE_EXCEPTIONS = None
    SECRET_KEY = 'mysecretkey'
    PERMANENT_SESSION_LIFETIME = '31 days, 0: 00:00'
    USE_X_SENDFILE = False
    SERVER_NAME = None
    APPLICATION_ROOT = '/'
    SESSION_COOKIE_NAME = 'session'
    SESSION_COOKIE_DOMAIN = None
    SESSION_COOKIE_PATH = None
    SESSION_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SECURE = False
    SESSION_COOKIE_SAMESITE = None
    SESSION_REFRESH_EACH_REQUEST = True
    MAX_CONTENT_LENGTH = None
    SEND_FILE_MAX_AGE_DEFAULT = None
    TRAP_BAD_REQUEST_ERRORS = None
    TRAP_HTTP_EXCEPTIONS = False
    EXPLAIN_TEMPLATE_LOADING = False
    PREFERRED_URL_SCHEME = 'http'
    TEMPLATES_AUTO_RELOAD = None
    MAX_COOKIE_SIZE = 4093


class TestingConfig:
    DEBUG = True
    TESTING = True
    PROPAGATE_EXCEPTIONS = True
    SECRET_KEY = 'mysecretkey'
    PERMANENT_SESSION_LIFETIME = '31 days, 0: 00:00'
    USE_X_SENDFILE = False
    SERVER_NAME = None
    APPLICATION_ROOT = '/'
    SESSION_COOKIE_NAME = 'session'
    SESSION_COOKIE_DOMAIN = None
    SESSION_COOKIE_PATH = None
    SESSION_COOKIE_HTTPONLY = True
    SESSION_COOKIE_SECURE = False
    SESSION_COOKIE_SAMESITE = None
    SESSION_REFRESH_EACH_REQUEST = True
    MAX_CONTENT_LENGTH = None
    SEND_FILE_MAX_AGE_DEFAULT = None
    TRAP_BAD_REQUEST_ERRORS = None
    TRAP_HTTP_EXCEPTIONS = False
    EXPLAIN_TEMPLATE_LOADING = False
    PREFERRED_URL_SCHEME = 'http'
    TEMPLATES_AUTO_RELOAD = None
    MAX_COOKIE_SIZE = 4093

test_server.py 内容:

import pytest
from server.server import create_app, app


@pytest.fixture()
def client_not_working():
    client = create_app('config.TestingConfig')
    with client.test_client() as testing_client:
        yield testing_client

@pytest.fixture()
def client_working():
    yield app.test_client()

fixture = client_not_working

def test_get_balance(fixture):
    response = fixture.get('/1/balance')
    assert response.status_code == 200
    assert response.headers['Content-Type'] == 'application/json'
    assert b'balance' in response.data
    assert response.json["balance"] == 0

当fixture设为client_working时测试可正常通过,但设为用于自定义配置的client_not_working时,访问/1/balance接口返回404错误,断言失败。请问哪里操作有误?


原因及解决方法

问题根源

client_not_working fixture调用create_app生成了全新的Flask实例,但这个新实例没有注册任何Flask-RESTful路由。原来的server.py中,Api初始化和路由注册逻辑是写在全局的,只对最开始创建的app实例生效,create_app函数内部没有这部分代码,导致新生成的测试用app完全没有接口路由,自然返回404。

而client_working fixture用的是全局已经完成路由注册的app实例,所以能正常访问接口。

解决方法(推荐应用工厂模式)

把Api和路由的注册逻辑移到create_app函数内部,让每个通过该函数创建的app实例都自带正确的路由配置:

修改后的server.py:

from flask import Flask
from flask_restful import Api, Resource

def create_app(config_obj):
    app = Flask(__name__)
    app.config.from_object(config_obj)
    
    # 将Api和路由注册逻辑移入函数内
    api = Api(app)
    
    class Balance(Resource):
        @staticmethod
        def get(user_id):
            balance = 0 * user_id
            return {"balance": balance}
    
    api.add_resource(Balance, "/<int:user_id>/balance")
    
    return app

# 全局app仍用默认配置初始化
app = create_app('config.DefaultConfig')

if __name__ == "__main__":
    app.run(debug=True)

这样修改后,client_not_working fixture生成的测试app会自动包含Balance接口的路由,测试就能正常通过了。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 11:36:21