I'm moving from using just Flask
and SQLAlchemy
with own setup for the database connection with engine and session to using 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. 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.
After moving to Flask-SQLAlchemy
I'm having trouble finding a good way to perform this kind of test. I was hoping to not have to mess too much with the individual tests, however if I alter my setUp
for example like this:
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.
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
.
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?
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
. I do push a app_context
which will be used by the queries I run.
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.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.