简体   繁体   English

使用 Flask-SQLAlchemy 进行测试时使用 app_context

[英]Usage of app_context when testing with Flask-SQLAlchemy

I'm moving from using just Flask and SQLAlchemy with own setup for the database connection with engine and session to using Flask-SQLAlchemy .我正在从仅使用FlaskSQLAlchemy与自己的数据库连接设置与引擎和 session 转向使用Flask-SQLAlchemy I have a lot of tests that look something like this:我有很多看起来像这样的测试:

def setUp(self):
    self.app = create_app()
    self.client = self.app.test_client()

def test_put_example(self):
    assert len(Example.query.all()) == 0

    data = [{
        "id": 1,
        "valid": True,
    }, {
        "id": 2,
        "valid": True,
    }, {
        "id": 3,
        "valid": True,
    }, {
        "id": 4,
        "valid": True,
    }, {
        "id": 5,
        "valid": False,  # Lets assume this value is illegal in some way and will not be accepted
    }]

    response = self.client.open('/v1/example', method='PUT', data=json.dumps(data))
    json_value = json.loads(response.data)
    assert not json_value['success'] and json_value['message'] == 'Unauthorized'

    assert len(Example.query.all()) == 0

Here I assume 0 entries in the database prior to testing the endpoint and 0 entries after testing the endpoint.在这里,我假设在测试端点之前数据库中有 0 个条目,在测试端点之后假设有 0 个条目。 When using Flask and SQLAlchemy separately this worked fine as the transaction was implicitly rolled back at the end of the request if there was no commit during the request.当分别使用FlaskSQLAlchemy时,这工作得很好,因为如果在请求期间没有commit ,事务会在请求结束时隐式回滚。

After moving to Flask-SQLAlchemy I'm having trouble finding a good way to perform this kind of test.迁移到Flask-SQLAlchemy后,我很难找到执行此类测试的好方法。 I was hoping to not have to mess too much with the individual tests, however if I alter my setUp for example like this:我希望不必过多地处理单个测试,但是如果我改变我的setUp ,例如这样:

def setUp(self):
    self.app = create_app()
    self.app.app_context().push()
    self.client = self.app.test_client()

Then the last check for assert len(Example.query.all()) == 0 fails, as it apparently didn't roll back the elements that were valid, so I get 4 as the length.然后最后一次检查assert len(Example.query.all()) == 0失败,因为它显然没有回滚有效的元素,所以我得到4作为长度。

It should be noted that when running the app I do appear to get the roll back that I desire, just not during testing.应该注意的是,在运行应用程序时,我确实似乎得到了我想要的回滚,只是在测试期间没有。

I see that I could potentially do with self.app.app_context() before each of the Example.query -calls, however that would mean many changes to individual tests, so I'd prefer to not have to do that, as well as not being entirely confident in my understanding of how to properly use the AppContext .我看到我可能会在每个Example.query调用之前with self.app.app_context() ,但这意味着对单个测试进行许多更改,所以我宁愿不必这样做,以及对我对如何正确使用AppContext的理解不完全有信心。

Is there any way I can properly provide an AppContext for my queries pre and post the endpoint testing without altering individual tests and still make the test_client do the roll back?有什么方法可以在端点测试之前和之后为我的查询正确提供AppContext而不改变单个测试并且仍然让test_client回滚?

I'm not sure this is an ideal approach but what I ended up doing so far was this:我不确定这是一种理想的方法,但到目前为止我最终做的是:

I no longer keep the test_client around, but rather wrap calls to it to initialize on demand with its own app_context .我不再保留test_client ,而是包装对它的调用以使用它自己的app_context按需初始化。 I do push a app_context which will be used by the queries I run.我确实推送了一个app_context ,它将被我运行的查询使用。

def setUp(self):
    self.app = create_app()
    self.context = self.app.app_context()
    self.context.push()

def tearDown(self):
    self.context.pop()

def client_open(self, url, method, data):
    with self.app.app_context():
        with self.app.test_client() as client:
            result = client.open(url, method=method, data=json.dumps(data))

def test_put_example(self):
    assert len(Example.query.all()) == 0

    data = [{
        "id": 1,
        "valid": True,
    }, {
        "id": 2,
        "valid": True,
    }, {
        "id": 3,
        "valid": True,
    }, {
        "id": 4,
        "valid": True,
    }, {
        "id": 5,
        "valid": False,  # Lets assume this value is illegal in some way and will not be accepted
    }]

    response = client_open('/v1/example', 'PUT', json.dumps(data))  # Wrapped call to test_client using own app_context
    json_value = json.loads(response.data)
    assert not json_value['success'] and json_value['message'] == 'Unauthorized'

    assert len(Example.query.all()) == 0

This way the app_context used by the test_client is torn down after use, and the app_context used by the queries is available throughout the test.这样app_context使用的test_client在使用后会被拆掉,而查询使用的app_context在整个测试过程中都是可用的。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM