【问题标题】:How to add headers to flask test_request_context?如何将标题添加到烧瓶 test_request_context?
【发布时间】:2019-12-18 16:17:08
【问题描述】:

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

@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()

我想在此测试请求上下文中添加“User-Agent”的标头,因为在我的应用程序中,我检查了用户的浏览器。我正在通过

在我的应用中检索浏览器名称
user_agent = flask.request.user_agent.browser

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

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 代码行插入到我的许多测试中的每一个中。

预期行为

我希望我可以在测试夹具中创建测试请求上下文时设置标头,例如:

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()

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

实际行为

虽然将 environ_base 添加到 test_request_context() 不会破坏夹具,但它不会设置 'User-Agent' 标头和

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

但它似乎并没有改变任何东西。我只是在 localhost 上运行烧瓶服务器,还没有部署,即基本上只是:

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

【问题讨论】:

    标签: python flask pytest


    【解决方案1】:

    测试客户端有一个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 发出测试请求时自动处理。在会话夹具中推送一个不会产生您想要的效果。在大多数情况下,您应该使用test_client 而不是test_request_context


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

    【讨论】:

      【解决方案2】:

      您可以在初始化时添加标题

      示例:

      from flask import request
      
      request_ctx = app.test_request_context(
          headers={'Authorization': 'Bearer XXXXX')}
      )
      
      request_ctx.push()
      
      request.headers
      # Output: EnvironHeaders([('Host', 'localhost'), ('Authorization', 'Bearer XXXXX')])
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-08
        • 2021-11-11
        • 2018-10-09
        • 2015-06-10
        • 2018-10-01
        相关资源
        最近更新 更多