2011-08-04 4 views
4

数日前にSQLAlchemyを使い始めたばかりですが、今は誰もが私の髪をゆるめる前に誰かに光を当ててくれることを願っています。unitAlertのSQLAlchemyセッションvoes

unittestを実行すると、以下のスニペットを参照してください。シーケンス内の最初のテストだけが合格です。テストtestPhysicalPrintは正常に動作しますが、NoResultFound例外でtestRecordingItemが失敗します。の行が見つかりませんでした。しかし、テストクラスからtestPhysicalPrintを削除すると、testRecordingItemが機能します。

問題はセッションと関係がありますが、実際にはそれを把握することはできません。誰もが疑問に思う場合

は、セットアップは次のとおりです。

  • のPython 3.1(Ubuntuの10.04パッケージ)
  • SQLAlchemyの0.7.2(easy_installを:ED)
  • のPostgreSQL 8.4.8(Ubuntuの10.04パッケージ)
  • PsycoPG2 2.4.2(easy_installed:ED)

Exemple試験:

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

UPDATE

ここで作業コードスニペットです。

# -*- 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() 

答えて

6

この動作の最も一般的な理由は、そのデータがテスト間で適切にクリーンアップされていないということです。このため、1つのテストのみを実行すると、そのテストが機能する理由がわかります。
setUpがすべてのテストの前に呼び出され、tearDown - 後になります。
あなたが達成したい内容に応じて、次の2つのオプションがあります。

  1. は、すべてのテストのために一度だけデータを作成します。
    この場合、Python-2.7 +またはPython-3.2 +をお持ちの場合はtearDownClassメソッドを使用できます。あなたのケースでは、ブール値のクラス変数で処理して、setUpにあるコードが複数回実行されないようにすることができます。
  2. 再作成するには、tearDownにあなたはすべてのデータを削除することを確認する必要があり、この場合には、すべてのテスト
    前にデータを。これはあなたが今やっていないことです.2番目のテストを実行すると、one()の呼び出しはオブジェクトを検出しないためではなく、条件を満たすオブジェクトが2つ以上見つかるため失敗します。

呼び出しシーケンスを理解するために、このコードの出力を確認します。

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 
+0

こんにちは!あなたに感謝します。私はBase.metadata.drop_all()を入れているtearDownで - それは問題のテーブルをドロップしないため、各テスト後にデータを削除しないだろうか? –

+0

あなたは正しいです。しかし何らかの理由で、データは実際には2回目に挿入されません。エンジンに 'echo = True'を設定し、生成されたSQL文を見ると、2回目にデータ行が挿入されないことがわかります。この時点で私は理由を知りません。それでも、オプション1を実装してデータを一度しか作成しないでください(テストしてもそれを削除しないと問題は回避されます)。 – van

+0

setUpでコミットを削除して、セッションがtearDownで閉じられる直前にロールバックを追加した後は、動作します。うーん... –

0

を私は私のtearDown方法としてこれを持って、それがために正常に動作しません私のテスト:

def tearDown (self): 
    """Cleans up after each test case.""" 
    sqlalchemy.orm.clear_mappers() 
+0

あなたの答えをありがとう。私はそれが必要な場合には、clear_mappersを心に留めておきます。好奇心が強い場合は、私の質問をコードの一部で更新しました。 –

関連する問題