Модульные тесты для запроса в SQLAlchemy

Как идти о тестировании запросов в SQLAlchemy? Например, предположим, что у нас есть это models.py

 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) ) 

и этот 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) 

Когда мы пытаемся запустить тест, он терпит неудачу, хотя две панели выглядят одинаково.

 $ 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) 

Одно из решений, которое я нашел, – сделать запрос для каждого отдельного экземпляра, который я ожидаю найти в запросе:

 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)) 

Тем не менее, это кажется мне довольно уродливым, и я даже не дошел до того, что у меня есть сложный отфильтрованный запрос, который я пытаюсь проверить. Есть ли более элегантное решение, или мне всегда приходится вручную создавать кучу отдельных запросов?

One Solution collect form web for “Модульные тесты для запроса в SQLAlchemy”

ваш оригинальный тест находится на правильном пути, вам просто нужно сделать одну из двух вещей: либо убедитесь, что два объекта Panel с одинаковым идентификатором первичного ключа сравниваются с True :

 class Panel(Base): # ... def __eq__(self, other): return isinstance(other, Panel) and other.id == self.id 

или вы можете организовать свой тест таким образом, чтобы убедиться, что вы проверяете тот же экземпляр Panel (потому что здесь мы используем карту идентификации ):

 class TestQuery(unittest.TestCase): def setUp(self): self.engine = create_engine('sqlite:///:memory:') self.session = Session(engine) Base.metadata.create_all(self.engine) self.panel = Panel(1, 'ion torrent', 'start') self.session.add(self.panel) self.session.commit() def tearDown(self): Base.metadata.drop_all(self.engine) def test_query_panel(self): expected = [self.panel] result = self.session.query(Panel).all() self.assertEqual(result, expected) 

что касается установки / отрыва двигателя / сеанса, я бы выбрал шаблон, в котором вы используете один движок для всех тестов, и если ваша схема фиксирована, единственная схема для всех тестов, то вы убедитесь, что данные, которые вы работаете с выполняется в транзакции, которая может быть откат. Session можно заставить работать таким образом, чтобы вызов commit() фактически не совершал «настоящую» транзакцию, завершая весь тест в явной Transaction . Этот пример используется в http://docs.sqlalchemy.org/en/rel_0_8/orm/session.html#joining-a-session-into-an-external-transaction . Наличие движка «: memory:» на каждом испытательном приборе займет много памяти и не будет масштабироваться в других базах данных, кроме SQLite.

  • Как заглушить методы Python без Mock
  • Python - скрученные и единичные тесты
  • Утилита Python устраняет необходимость в модульных тестах?
  • В Python, какой хороший шаблон для отключения определенного кода во время модульных тестов?
  • Обнаружение и тестирование Python
  • Издевательство над методом вне класса
  • Как сравнить две вложенные структуры данных для unittesting?
  • Python mock, django и запросы
  • Python - лучший язык программирования в мире.