几天前我刚刚开始使用 SQLAlchemy,现在我遇到了一个问题,我希望任何人都可以在我失去所有头发之前弄清楚。
当我运行单元测试时,请参阅下面的代码片段,只有序列中的第一个测试通过。测试 testPhysicalPrint 工作正常,但 testRecordingItem 因 NoResultFound 异常而失败 - 未找到 one() 的行。但是如果我从测试类中删除 testPhysicalPrint,那么 testRecordingItem 就可以工作了。
我认为问题与 session 有关,但我无法真正掌握它。
如果有人想知道,设置如下:
示例测试:
class TestSchema(unittest.TestCase):
test_items = [
# Some parent class products
PrintItem(key='p1', title='Possession', dimension='30x24'),
PrintItem(key='p2', title='Andrzej Żuławski - a director', dimension='22x14'),
DigitalItem(key='d1', title='Every Man His Own University', url='http://www.gutenberg.org/files/36955/36955-h/36955-h.htm'),
DigitalItem(key='d2', title='City Ballads', url='http://www.gutenberg.org/files/36954/36954-h/36954-h.htm'),
]
def testPrintItem(self):
item = self.session.query(PrintItem).filter(PrintItem.key == 'p1').one()
assert item.title == 'Possession', 'Title mismatch'
def testDigitalItem(self):
item2 = self.session.query(DigitalItem).filter(DigitalItem.key == 'd2').one()
assert item2.title == 'City Ballads', 'Title mismatch'
def setUp(self):
Base.metadata.create_all()
self.session = DBSession()
self.session.add_all(self.test_items)
self.session.commit()
def tearDown(self):
self.session.close()
Base.metadata.drop_all()
if __name__ == '__main__':
unittest.main()
更新
这是工作代码片段。
# -*- coding: utf-8 -*-
import time
import unittest
from sqlalchemy import *
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import *
Base = declarative_base()
engine = create_engine('sqlite:///testdb', echo=False)
DBSession = sessionmaker(bind=engine)
class ItemMixin(object):
"""
Commons attributes for items, ie books, DVD:s...
"""
__tablename__ = 'testitems'
__table_args__ = {'extend_existing':True}
id = Column(Integer, autoincrement=True, primary_key=True)
key = Column(Unicode(16), unique=True, nullable=False)
title = Column(UnicodeText, default=None)
item_type = Column(Unicode(20), default=None)
__mapper_args__ = {'polymorphic_on': item_type}
def __init__(self, key, title=None):
self.key = key
self.title = title
class FooItem(Base, ItemMixin):
foo = Column(UnicodeText, default=None)
__mapper_args__ = {'polymorphic_identity':'foo'}
def __init__(self, foo=None, **kwargs):
ItemMixin.__init__(self, **kwargs)
self.foo = foo
class BarItem(Base, ItemMixin):
bar = Column(UnicodeText, default=None)
__mapper_args__ = {'polymorphic_identity':'bar'}
def __init__(self, bar=None, **kwargs):
ItemMixin.__init__(self, **kwargs)
self.bar = bar
# Tests
class TestSchema(unittest.TestCase):
# Class variables
is_setup = False
session = None
metadata = None
test_items = [
FooItem(key='f1', title='Possession', foo='Hello'),
FooItem(key='f2', title='Andrzej Żuławsk', foo='World'),
BarItem(key='b1', title='Wikipedia', bar='World'),
BarItem(key='b2', title='City Ballads', bar='Hello'),
]
def testFooItem(self):
print ('Test Foo Item')
item = self.__class__.session.query(FooItem).filter(FooItem.key == 'f1').first()
assert item.title == 'Possession', 'Title mismatch'
def testBarItem(self):
print ('Test Bar Item')
item = self.__class__.session.query(BarItem).filter(BarItem.key == 'b2').first()
assert item.title == 'City Ballads', 'Title mismatch'
def setUp(self):
if not self.__class__.is_setup:
self.__class__.session = DBSession()
self.metadata = Base.metadata
self.metadata.bind = engine
self.metadata.drop_all() # Drop table
self.metadata.create_all() # Create tables
self.__class__.session.add_all(self.test_items) # Add data
self.__class__.session.commit() # Commit
self.__class__.is_setup = True
def tearDown(self):
if self.__class__.is_setup:
self.__class__.session.close()
# Just for Python >=2.7 or >=3.2
@classmethod
def setUpClass(cls):
pass
#Just for Python >=2.7 or >=3.2
@classmethod
def tearDownClass(cls):
pass
if __name__ == '__main__':
unittest.main()
最佳答案
这种行为最可能的原因是在测试之间没有正确清理数据。这解释了为什么当您只运行一项测试时它会起作用。
setUp在每次测试之前调用,并且 tearDown - 后。
根据您想要实现的目标,您有两种选择:
在这种情况下,如果你有 Python-2.7+ 或 Python-3.2+,你可以使用 tearDownClass方法。在您的情况下,您可以使用 bool 类变量来处理它以防止您在
setUp
中的代码。运行不止一次。 在这种情况下,您需要确保在
tearDown
中你删除所有数据。这是您现在没有做的事情,我怀疑在运行第二个测试时,调用 one()
失败不是因为它没有找到一个对象,而是因为它找到了更多两个符合条件的对象。 检查此代码的输出以了解调用序列:
import unittest
class TestSchema(unittest.TestCase):
def testOne(self):
print '==testOne'
def testTwo(self):
print '==testTwo'
def setUp(self):
print '>>setUp'
def tearDown(self):
print '<<tearDown'
@classmethod
def setUpClass():
print '>>setUpClass'
@classmethod
def tearDownClass():
print '<<tearDownClass'
if __name__ == '__main__':
unittest.main()
输出:
>>setUp
==testOne
<<tearDown
>>setUp
==testTwo
<<tearDown
关于单元测试中的 SQLAlchemy session 投票,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6941368/