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

如何在Flask测试代码中启动测试服务器?

Flask端到端测试中启动测试服务器的问题

运行Miguel Grinberg《Flask Web Development 2e》第15章的Selenium端到端测试时,控制台出现以下错误:

  • Ignoring a call to 'app.run()' that would block the current 'flask' CLI command.
    Only call 'app.run()' in an 'if name == "main"' guard.

随后浏览器显示“Firefox无法建立连接...”,测试服务器未成功启动。

测试代码(tests/test_selenium.py)

import threading
import unittest
from selenium import webdriver

from app import create_app, db, fake
from app.models import Role, User


class SeleniumTestCase(unittest.TestCase):
    browser = None

    @classmethod
    def setUpClass(cls) -> None:
        try:
            cls.browser = webdriver.Firefox()
        except Exception as e:
            pass
        
        if cls.browser:
            cls.app = create_app('testing')
            cls.app_context = cls.app.app_context()
            cls.app_context.push()

            import logging
            logger = logging.getLogger('werkzeug')
            logger.setLevel('ERROR')

            db.create_all()
            Role.insert_roles()
            fake.users(10)
            fake.posts(10)

            admin_role = Role.query.filter_by(permissions=0xff).first()
            admin = User(email='john@example.com', password='cat', username='john', role=admin_role, confirmed=True)
            db.session.add(admin)
            db.session.commit()

            cls.server_thread = threading.Thread(
                target=cls.app.run,
                kwargs={
                    'debug': 'false',
                    'use_reloader': False,
                    'use_debugger': False,
                    'host': '0.0.0.0',
                    'port': 5000
                }
            )
            cls.server_thread.start()
    
    @classmethod
    def tearDownClass(cls) -> None:
        if cls.browser:
            cls.browser.get('http://localhost:5000/shutdown')
            cls.browser.quit()
            cls.server_thread.join()

            db.drop_all()
            db.session.remove()

            cls.app_context.pop()
    
    def setUp(self) -> None:
        if not self.browser:
            self.skipTest('Web browser not available')
    
    def tearDown(self) -> None:
        pass

    def test_admin_home_page(self):
        self.browser.get('http://localhost:5000/')   # fails here
        self.assertRegex(self.browser.page_source, 'Hello,\s+Stranger!')

        self.fail('Finish the test!')

补充说明

曾尝试使用Flask-Testing,但该库已无人维护。问题根源是显式调用app.run()与Flask CLI的隐式调用冲突,但不调用则测试服务器无法启动。希望通过现有Flask CLI的test命令运行该测试,当前CLI命令代码如下:

@app.cli.command()
@click.argument('test_names', nargs=-1)
def test(coverage, test_names):
    """Run the unit tests"""
    import unittest
    if test_names:
        tests = unittest.TestLoader().loadTestsFromNames(test_names)
    else:
        tests = unittest.TestLoader().discover('tests')
    unittest.TextTestRunner(verbosity=2).run(tests)

通过if __name__ == "__main__"运行会绕过现有测试加载/运行流程,因此需要其他解决方案。


解决方案

方法一:使用Werkzeug的run_simple替代app.run()

直接调用Werkzeug底层的服务器启动方法,绕开Flask的app.run()封装,避免CLI冲突:

  1. 导入run_simple:
from werkzeug.serving import run_simple
  1. 修改线程启动代码:
cls.server_thread = threading.Thread(
    target=run_simple,
    args=('0.0.0.0', 5000, cls.app),
    kwargs={
        'use_reloader': False,
        'use_debugger': False,
        'debug': False
    }
)

方法二:临时禁用CLI冲突检查(不推荐)

通过修改Flask内部状态跳过检查,依赖内部实现,可能随版本失效:
在创建测试app后添加:

cls.app._got_first_request = True

方法三:确保shutdown路由正常工作

测试结束后需要关闭服务器,需确保app中已实现/shutdown路由:

from flask import request

@app.route('/shutdown')
def shutdown():
    func = request.environ.get('werkzeug.server.shutdown')
    if func is None:
        raise RuntimeError('Not running with the Werkzeug Server')
    func()
    return 'Server shutting down...'

内容的提问来源于stack exchange,提问作者Darwin von Corax

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 00:05:33