Python 无法在Flask测试用例会话中检索数据库对象

Python 无法在Flask测试用例会话中检索数据库对象,python,unit-testing,flask,sqlalchemy,factory-boy,Python,Unit Testing,Flask,Sqlalchemy,Factory Boy,我正在测试一个使用flaskrestful、sqlalchemy、flasksqlalchemy和FactoryBoy创建的API 我遇到了一个奇怪的问题,在使用factory的GET请求之前创建的对象可用,但在post/put调用之前创建的对象不可用 我已经基于烧瓶测试设置了一个测试用例类: # tests/common.py from flask_testing import TestCase as FlaskTestCase from app import create_app from

我正在测试一个使用
flaskrestful
sqlalchemy
flasksqlalchemy
FactoryBoy
创建的API

我遇到了一个奇怪的问题,在使用
factory
GET
请求之前创建的对象可用,但在post/put调用之前创建的对象不可用

我已经基于烧瓶测试设置了一个测试用例类:

# 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\u update\u项中
我收到一个404。在进入
self.client.put
之前,检查数据库会显示新的
项已创建。但是,当我们到达资源中的
put
方法时,
db.session(Item).query.all()
返回一个空数组

烧瓶测试
文档中,我发现了以下段落:


另一个问题是Flask SQLAlchemy也会在每个请求结束时删除会话实例(任何使用SQLAlchemy的线程安全应用程序都应该在作用域为_的会话中删除)。因此,每次调用client.get()或其他客户机方法时,都会清除会话以及添加到会话中的任何对象。


我相信问题在于如何处理会话,但还不能拿出任何解决方案来确保我的测试通过。另一个有趣的观察结果是,对于
self.client.put
self.client.post
,如果我将发布的数据更改为
self.client.put('/some/url',data={'symbol':symbol})
,对象将在会话中可用。

好的,找到了一种复杂的方法来解决这个问题。我认为调用
request.get_json
会在其他地方实例化一个会话。解决方案是覆盖json数据的发布方式

测试/common.py
中:

import json

from flask_testing import TestCase as FlaskTestCase
from flask.testing import FlaskClient

from app import create_app
from database import db
from config import TestConfig


class TestClient(FlaskClient):
    def open(self, *args, **kwargs):
        if 'json' in kwargs:
            kwargs['data'] = json.dumps(kwargs.pop('json'))
            kwargs['content_type'] = 'application/json'
        return super(TestClient, self).open(*args, **kwargs)


class TestCase(FlaskTestCase):
    def create_app(self):
        app = create_app(TestConfig)
        app.test_client_class = TestClient
        return app

    def setUp(self):
        db.create_all()

    def tearDown(self):
        db.session.remove()
        db.drop_all()

因此,我们基本上是将测试客户机中post/put调用中的任何
json
kwargs转换为数据,并将
content\u type
设置为json。您可能需要看看SQLAlchemy会话处理

factory_boy文档介绍了几个选项:

工厂似乎在SQLAlchemy会话中创建对象,但该会话未写入数据库。 当您的代码进入flask端时,该上下文可能正在使用另一个到数据库的连接(请参阅您引用的
flask testing
doc),因此看不到尚未提交的对象