用pytest保留响应上下文测试瓶应用程序

时间:2016-04-15 17:24:19

标签: python flask pytest

我正在使用py.test测试带有以下代码的烧瓶应用程序:

response = flask_app_test_client.post('/users', data=json.dumps(user))
assert response.status_code == 201
assert response.content_type == 'application/json'
assert isinstance(response.json, dict)
assert set(response.json.keys()) >= {'id', 'status', 'created_at', 'updated_at'}
assert response.json['name'] == user['name']
assert response.json['status'] == 'pending'

当某些断言失败时,我会得到类似的东西:

            response = test_client.post('/users', data=json.dumps(user))
    >       assert response.status_code == 201
    E       assert 400 == 201
    E        +  where 400 = <JSONResponse streamed [400 BAD REQUEST]>.status_code
    ============== 1 failed, 3 passed in 0.10 seconds ===================

我做了很多TDD,所以我希望我的测试在开发过程中经常失败。我的问题是断言错误消息没有其他响应数据(正文,标题等)是没用的。

我只在输出中得到response.status_code为400但我没有得到响应正文中的错误描述:{"errors": ["username is already taken", "email is required"]}。理想情况下,当断言失败时,我希望完整转储请求和响应(标题+正文)。

如何在每个失败的断言上打印响应摘要?

3 个答案:

答案 0 :(得分:0)

Assert statement graamar

assert response.status_code == 201, "Anything you want"

你可以像你想要的那样冗长。你也可以使用UnitTest的helper methods套件 -  没有测试用例类通过这一点滥用 - https://github.com/nose-devs/nose2/blob/master/nose2/tools/such.py#L34

答案 1 :(得分:0)

我想出了两种不同的解决方案。

解决方案#1:尝试/捕捉

try:
    assert response.status_code == 201
    assert response.content_type == 'application/json'
    assert isinstance(response.json, dict)
    assert set(response.json.keys()) >= {'id', 'status', 'created_at', 'updated_at'}
    assert response.json['name'] == user['name']
    assert response.json['status'] == 'pending'
except AssertionError as e:
    except AssertionError as e:
    raise ResponseAssertionError(e, response)

class ResponseAssertionError(AssertionError):
    def __init__(self, e, response):
        response_dump = "\n +  where full response was:\n" \
                        "HTTP/1.1 {}\n" \
                        "{}{}\n".format(response.status, response.headers, response.json)

        self.args = (e.args[0] + response_dump,)

解决方案#2:不需要尝试/捕获(如果repr太长,有时会被切断......)

扩展并覆盖Flask响应对象

import json
class JSONResponse(Response):

    def __repr__(self):
        headers = {}
        while len(self.headers) > 0:
            tuple_ = self.headers.popitem()
            headers[tuple_[0]] = tuple_[1]

        data = {
            'status': self.status,
            'headers': headers,
            'body': self.json
        }
        return json.dumps(data)

    @pytest.fixture(scope='session')
    def test_client(flask_app):
        flask_app.response_class = JSONResponse
        return flask_app.test_client()

答案 2 :(得分:0)

我知道这是一个较旧的问题,但是Pytest有一个选项--pdb,如果测试失败,该选项将使您跳入PDB Shell。一种非常方便的“四处浏览”的方法,而不必将大量的内容传递给异常消息。