Я тестирую API, созданный с использованием flask-restful
, sqlalchemy
, flask-sqlalchemy
и factory-boy
.
Я столкнулся со странной проблемой, когда объекты, созданные до GET
запросов с использованием factory
, доступны, но объекты, созданные до вызовов post / put, недоступны.
Я настроил класс тестового примера на основе flask-testing
:
# tests/common.py
from flask_testing import TestCase as FlaskTestCase
from app import create_app
from database import db
from config import TestConfig
class TestCase(FlaskTestCase):
def create_app(self):
return create_app(TestConfig)
def setUp(self):
db.create_all()
def tearDown(self):
db.session.remove()
db.drop_all()
Испытательная фабрика:
# tests/factory.py
import factory
from database import db
from ..models import Item
class ItemFactory(factory.alchemy.SQLAlchemyModelFactory):
class Meta:
model = Item
sqlalchemy_session = db.session
Ресурсы:
# resources.py
from flask import request
from flask_restful import Resource
from database import db
from .models import Item
from .serializers import ItemSerializer
class ItemResource(Resource):
def get(self, symbol):
obj = db.session(Item).filter(Item.symbol == symbol).first_or_404()
return ItemSerializer(obj).data
def put(self, symbol):
params = request.get_json(silent=True)
query = db.session(Item).filter(Item.symbol == symbol).update(params)
db.session.commit()
obj = db.session(Item).filter(Item.symbol == symbol).first_or_404()
return ItemSerializer(obj).data
Тесты:
# tests/test_resources.py
import json
from tests.common import TestCase
from tests.factory import ItemFactory
def parse_response(response):
return json.loads(response.get_data().decode())
class ResourcesTest(TestCase):
def test_get_item(self):
symbol = 'TEST'
ItemFactory(symbol=symbol)
response = self.client.get('/api/v1/items/%s' % symbol)
results = parse_response(response)
self.assertEqual(response.status_code, 200)
self.assertEqual(results['symbol'], symbol)
def test_update_item(self):
symbol = 'TEST'
new_symbol = 'TEST_NEW'
ItemFactory(symbol=symbol)
response = self.client.put('/api/v1/items/%s' % symbol, json={'symbol': new_symbol})
results = parse_response(response)
self.assertEqual(response.status_code, 200)
В test_update_item
вместо этого я получаю 404. Прежде чем мы введем self.client.put
, проверка базы данных показывает, что новый Item
был создан. Однако когда мы достигаем метода put
в ресурсе, db.session(Item).query.all()
возвращает пустой массив.
Из flask-testing
документации я заметил этот абзац:
Another gotcha is that Flask-SQLAlchemy also removes the session instance at the end of every request (as should any thread safe application using SQLAlchemy with scoped_session). Therefore the session is cleared along with any objects added to it every time you call client.get() or another client method.
Я полагаю, что проблема заключается в способе обработки сеансов, но я не смог предложить какие-либо решения для обеспечения прохождения моих тестов. Еще одним интересным наблюдением было то, что для self.client.put
или self.client.post
, если я изменю данные, публикуемые как self.client.put('/some/url', data={'symbol': symbol})
, объекты будут доступны в сеансе.