Come si fa a testare le query in SQLAlchemy? Per esempio supponiamo di avere questo models.py
Test unitari per query in SQLAlchemy
from sqlalchemy import (
Column,
Integer,
String,
)
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Panel(Base):
__tablename__ = 'Panels'
id = Column(Integer, primary_key=True)
category = Column(Integer, nullable=False)
platform = Column(String, nullable=False)
region = Column(String, nullable=False)
def __init__(self, category, platform, region):
self.category = category
self.platform = platform
self.region = region
def __repr__(self):
return (
"<Panel('{self.category}', '{self.platform}', "
"'{self.region}')>".format(self=self)
)
e questo tests.py
import unittest
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import Base, Panel
class TestQuery(unittest.TestCase):
engine = create_engine('sqlite:///:memory:')
Session = sessionmaker(bind=engine)
session = Session()
def setUp(self):
Base.metadata.create_all(self.engine)
self.session.add(Panel(1, 'ion torrent', 'start'))
self.session.commit()
def tearDown(self):
Base.metadata.drop_all(self.engine)
def test_query_panel(self):
expected = [Panel(1, 'ion torrent', 'start')]
result = self.session.query(Panel).all()
self.assertEqual(result, expected)
Quando abbiamo provare a eseguire il test, non riesce, anche se i due pannelli appaiono identici.
$ nosetests
F
======================================================================
FAIL: test_query_panel (tests.TestQuery)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/Users/clasher/tmp/tests.py", line 31, in test_query_panel
self.assertEqual(result, expected)
AssertionError: Lists differ: [<Panel('1', 'ion torrent', 's... != [<Panel('1', 'ion torrent', 's...
First differing element 0:
<Panel('1', 'ion torrent', 'start')>
<Panel('1', 'ion torrent', 'start')>
[<Panel('1', 'ion torrent', 'start')>, <Panel('2', 'ion torrent', 'end')>]
----------------------------------------------------------------------
Ran 1 test in 0.063s
FAILED (failures=1)
Una soluzione che ho trovato è quello di fare una query per ogni singola istanza mi aspetto di trovare nella query:
class TestQuery(unittest.TestCase):
...
def test_query_panel(self):
expected = [
(1, 'ion torrent', 'start'),
(2, 'ion torrent', 'end')
]
successful = True
# Check to make sure every expected item is in the query
try:
for category, platform, region in expected:
self.session.query(Panel).filter_by(
category=category, platform=platform,
region=region).one()
except (NoResultFound, MultipleResultsFound):
successful = False
self.assertTrue(successful)
# Check to make sure no unexpected items are in the query
self.assertEqual(self.session.query(Panel).count(),
len(expected))
Questo mi sembra abbastanza brutto, però, e io sono nemmeno arrivando al punto in cui ho una query filtrata complessa che sto provando a testare. C'è una soluzione più elegante, o devo sempre fare manualmente una serie di singole query?
L'idea chiave qui è che è necessario creare un'istanza di tutti gli oggetti durante l'installazione, trattenerli assegnandoli come attributi a 'self' e recuperarli in un secondo momento, non eseguendo nuovamente una query sul database, ma attraverso quei' self'. attributi. Inoltre, l'implementazione di '__eq__' non era necessaria; sembra che SQLAlchemy restituirà la stessa identica istanza di un modello (ad esempio, 'created_model_instance is instance_from_query' restituisce' True'). Infine, sarebbe utile rivedere la risposta per utilizzare il modello di rollback della transazione, anche se è possibile dedurre dalla lettura della documentazione SQLAlchemy sul link fornito. – gotgenes