python - 如何将标题添加到flask test_request_context?

标签 python flask pytest

我有一个测试装置可以在我的 Flask 应用程序中创建一个测试客户端:

@pytest.fixture(scope='session') 
def test_client():
    """ Create the application and the test client. 
    """
    print('----------Setup test client----------')
    app = create_app(config_class=config.TestConfig)
    testing_client = app.test_client()

    ctx = app.test_request_context() 
    ctx.push()
    yield testing_client # this is where the testing happens
    print('-------Teardown test client--------')
    ctx.pop()

我想将“用户代理”的 header 添加到此测试请求上下文中,因为在我的应用程序中我检查了用户的浏览器。我正在通过以下方式检索我的应用程序中的浏览器名称

user_agent = flask.request.user_agent.browser

如果我使用上面的测试客户端,这一行将返回 None 。虽然我可以在单个测试中的单个请求中成功设置“User-Agent” header ,例如:

user_agent_str = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'

response = test_client.get('/some_flask_route',
        environ_base={'HTTP_USER_AGENT': user_agent_str},
        follow_redirects=True)

这样做之后:flask.request.user_agent.browser按预期返回 'chrome'。

然而,这是非常多余的,因为它需要我将 environ_base 代码行插入到我的许多测试中的每一个中。

预期行为

我希望在我的测试装置中创建测试请求上下文时可以设置 header ,例如:

user_agent_str = 'Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/78.0.3904.108 Safari/537.36'

@pytest.fixture(scope='session') 
def test_client():
    """ Create the application and the test client. 
    """
    print('----------Setup test client----------')
    app = create_app(config_class=config.TestConfig)
    testing_client = app.test_client()
    ctx = app.test_request_context(environ_base={'HTTP_USER_AGENT': user_agent_str}) 
    ctx.push()
    yield testing_client # this is where the testing happens
    print('-------Teardown test client--------')
    ctx.pop()

这将为所有请求设置环境,从而无需在我的每个请求中都设置 environment_base。

实际行为

虽然将environ_base 添加到test_request_context() 中不会破坏fixture,但它不会设置“User-Agent” header 和

flask.request.user_agent.browser

返回无。

环境
  • Python 版本:3.7.3
  • flask 版本:1.1.1
  • Werkzeug 版本:0.15.4

  • 我已经尝试了这里问题中建议的解决方案:Setting (mocking) request headers for Flask app unit test

    但它似乎没有改变任何东西。我只是在没有部署的情况下在本地主机上运行 Flask 服务器,即基本上只是:

    app = Flask(__name__)
    app.run(host='127.0.0.1',port=5000,debug=True)
    

    最佳答案

    测试客户端有一个 environ_base在构建每个请求时设置默认环境的属性。

    c = app.test_client()
    c.environ_base["HTTP_USER_AGENT"] = "Firefox/71.0"
    

    要更好地控制传递给每个请求的内容,FlaskClient可以被子类化以覆盖 open :

    class CustomClient(FlaskClient):
        def open(self, *args, **kwargs):
            headers = kwargs.setdefault("headers", {})
            headers.setdefault("User-Agent", "Firefox/71.0")
            return super().open(*args, **kwargs)
    
    
    app.test_client_class = CustomClient
    
    c = app.test_client()
    assert c.get("/browser") == "firefox"
    

    同样,Flask可以被子类化以覆盖 test_request_context :

    class CustomFlask(Flask):
        def test_request_context(self, *args, **kwargs):
            headers = kwargs.setdefault("headers", {})
            headers.setdefault("User-Agent", "Firefox/71.0")
            return super().test_request_context(*args, **kwargs)
    
    app = CustomFlask()
    
    with app.test_request_client():
        assert browser() == "firefox"
    

    不要为所有测试全局推送测试请求上下文。应该为每个请求创建一个新的上下文,并在使用 client 发出测试请求时自动处理。 .在 session 装置中推送一个不会产生您想要的效果。在大多数情况下,您应该使用 test_clienttest_request_context .

    重新考虑您首先依赖用户代理的原因。以用户代理为基础的应用程序行为通常是糟糕的设计,因为浏览器会误报它们并且功能会随着时间的推移而改变。

    关于python - 如何将标题添加到flask test_request_context?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59396114/

    相关文章:

    Python .get 嵌套 Json 值

    Python sklearn OneVsRestClassifier : Score function gives ValueError

    python - 如何处理 sklearn GradientBoostingClassifier 中的分类变量?

    python - 我如何配置 python/flask 以使用 Windows 防火墙进行公共(public)访问

    python - 使用 pyspark dataframe : how to mock up . repartition() 链式函数测试代码时?

    python - 使用 subprocess.Popen 时,使用可执行参数与将 exe 路径作为命令中的第一项有什么区别?

    python - 基于 URL 动态路由到 Flask 操作

    python - 如何在新的应用程序部署中将数据库与 Flask-Migrate 同步?

    python - pytest无法访问django类

    python - 如何通过检查传递给 pytest_runtest_teardown 的 Item 对象来确定测试是通过还是失败?