Использование app_context при тестировании с Flask-SQLAlchemy - PullRequest
0 голосов
/ 08 октября 2019

Я перехожу от использования Flask и SQLAlchemy с собственной настройкой соединения с базой данных с движком и сеансом к использованию Flask-SQLAlchemy. У меня есть много тестов, которые выглядят примерно так:

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

Здесь я предполагаю 0 записей в базе данных до тестирования конечной точки и 0 записей после тестирования конечной точки. При использовании Flask и SQLAlchemy по отдельности это работало нормально, поскольку транзакция неявно откатывалась в конце запроса, если во время запроса не было commit.

После перехода на Flask-SQLAlchemy IУ меня проблемы с поиском хорошего способа выполнить этот вид теста. Я надеялся, что мне не придется слишком много возиться с отдельными тестами, однако, если я изменю свой setUp, например, следующим образом:

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

Тогда последняя проверка для assert len(Example.query.all()) == 0 завершится неудачно, так как, по-видимому,не откатывал элементы, которые были действительны, поэтому я получаю 4 в качестве длины.

Следует отметить, что при запуске приложения я получаю откат, который мне нужен, только не во время тестирования.

Я вижу, что потенциально могуделать with self.app.app_context() перед каждым из Example.query -вызовов, однако это будет означать много изменений в отдельных тестах, поэтому я предпочел бы не делать этого, а также не быть полностью уверенным в своем понимании того, как правильноиспользуйте AppContext.

Можно ли как-нибудь правильно предоставить AppContext для своих запросов до и после тестирования конечной точки без изменения отдельных тестов и при этом test_client сделать откат?

1 Ответ

0 голосов
/ 09 октября 2019

Я не уверен, что это идеальный подход, но то, что я до сих пор делал, заключалось в следующем:

Я больше не держу test_client вокруг, а скорее обращаюсь к нему для инициализации по требованиюсо своим app_context. Я нажимаю 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

Таким образом app_context, используемый test_client, разрушается после использования, а app_context используетсяпо запросам доступен на протяжении всего теста.

...