2014-10-06 12 views
9

Testlerimin çalışması uzun sürüyor ve testler arasında bırakma ve tablolar oluşturma yerine testler arasında işlemler geri almayı deniyorum.Geri Alma Flask'taki testler arasındaki işlemler arasındaki işlemler

Bazı testlerde, birden çok işlem yaptığım sorunlardır.

DÜZENLEME: testler hızlı

İşte Test için kullanılan Taban sınıftır çalışacak şekilde nasıl test arasındaki işlemleri geri alma yoktur.

import unittest 
from app import create_app 
from app.core import db 
from test_client import TestClient, TestResponse 


class TestBase(unittest.TestCase): 
    def setUp(self): 
     self.app = create_app('testing') 
     self.app_context = self.app.app_context() 
     self.app_context.push() 
     self.app.response_class = TestResponse 
     self.app.test_client_class = TestClient 
     db.create_all() 

    def tearDown(self): 
     db.session.remove() 
     db.drop_all() 
     db.get_engine(self.app).dispose() 
     self.app_context.pop() 

İşte işlemleri geri alma girişimi.

class TestBase(unittest.TestCase): 
    @classmethod 
    def setUpClass(cls): 
     cls.app = create_app('testing') 
     cls.app_context = cls.app.app_context() 
     cls.app_context.push() 
     cls.app.response_class = TestResponse 
     cls.app.test_client_class = TestClient 

     db.create_all() 

    @classmethod 
    def tearDown(cls): 
     db.session.remove() 
     db.drop_all() 
     db.get_engine(cls.app).dispose() 

    def setUp(self): 
     self.app_content = self.app.app_context() 
     self.app_content.push() 
     db.session.begin(subtransactions=True) 

    def tearDown(self): 
     db.session.rollback() 
     db.session.close() 

     self.app_context.pop() 
+0

iken. Çalışan veritabanı komutlarını test etmeniz gerekmez. Ünite testleri iş mantığı içindir, bunun gibi sorunları önlemek için sahte bir veritabanı oluşturabilir ve veritabanınızı bozma riskiniz yoktur. – CodeLikeBeaker

+1

Test için bellek içi db kullanıyor musunuz? Aksi takdirde, bu testler önemli ölçüde hızlandırabilir. – jsnjack

+0

PostgreSQL'de bir test veritabanı kullanıyorum. – Siecje

cevap

3

Session.begin_nested. Sürece tüm testler düzgün bir alt işlemlerini kapatmak için commit aradığınız gibi ben sadece daha hızlı olması gerektiği gibi, gözlerimi, görünüyor

session.begin_nested() 
run_test(session) 
session.rollback() 

yapabiliriz. Ancak veritabanınıza bir dereceye kadar bağlı olabilir. Bu cevap değil teknik sorunuza cevap yok iken

+0

db.session.begin_nested() ile "sqlalchemy.exc.InvalidRequestError: db.session.begin (subtransactions = True) db.session.begin ile değiştirildi. Bu oturumun işlemi, önceki bir özel durum nedeniyle geri alındı. Bu oturumda yeni işlem, ilk olarak Session.rollback().Özgün istisna: (IntegrityError) yinelenen anahtar değeri benzersiz bir kısıtlamayı ihlal ediyor "ix_users_email" DETAY: Anahtar (e-posta) = ([email protected]) zaten var. " – Siecje

+0

@Siecje bu hatanın farklı bir problemden kaynaklandığını, büyük olasılıkla Testlerinize başlamadan önce DB'nizi temizlemeniz gerekir. Eğer testi çalıştırırken bir istisna meydana gelirse, geri alma işlemi gerçekleşmeden önce bir şeyler durur.O zaman testi tekrar çalıştırdığınızda, tablo bu hataya neden olan verilerle kısmen dolu olarak başlayacaktır. –

+0

Doğru yanıt budur – ffleandro

0

, onlar çalıştırmak için uzun bir zaman alabilir çünkü haddeleme geri testlerinin arkasındaki sebep olduğunu bahsetti mi, bu yüzden alternatif bir çözüm sunmak istiyoruz:

Test paketinizi çalıştırmaya başladığınızda ve tüm testleriniz bittiğinde bunları bıraktığınızda tablolarınızı oluşturun. Daha sonra, her bir testin tearDown'u tamamen düşürmek yerine empty the tables yapın.

Testlerimi, orijinal posterin istediği gibi geri alma yoluyla nasıl hızlandıracağımı anlamaya çalışırken uzun zaman harcadım ve iç içe geçmiş işlemler içerdiğinden çok kafa karıştırıcı olduğunu fark ettim. Ancak, yukarıdaki yaklaşımı denediğimde, test takımım iki katı kadar hızlı koşuyordu ki bu da benim için yeterince iyiydi.

+2

Bu, herşeyi tamamen sıfırlamıyor, özellikle diziler (PK ID numaralandırma gibi) sıfırlanmaz. –

4

Bunu yapmak için kullandığımız kod budur. __start_transaction uygulamasının kurulumunuzda çağırıldığından emin olun ve teardown'ınızda __close_transaction (flask-sqlalchemy kullanıyorsanız bir uygulama içeriğiyle). Başka bir ipucu olarak, yalnızca bu kodu veritabanına isabet eden sınama durumlarında devralın ve veritabanı işlevinizi kontrol eden koddan iş mantığınızı kontrol eden koddan ayırın, çünkü bunlar hala WAY'ı daha hızlı çalıştıracaktır.

def __start_transaction(self): 
    # Create a db session outside of the ORM that we can roll back 
    self.connection = db.engine.connect() 
    self.trans = self.connection.begin() 

    # bind db.session to that connection, and start a nested transaction 
    db.session = db.create_scoped_session(options={'bind': self.connection}) 
    db.session.begin_nested() 

    # sets a listener on db.session so that whenever the transaction ends- 
    # commit() or rollback() - it restarts the nested transaction 
    @event.listens_for(db.session, "after_transaction_end") 
    def restart_savepoint(session, transaction): 
     if transaction.nested and not transaction._parent.nested: 
      session.begin_nested() 

    self.__after_transaction_end_listener = restart_savepoint 

def __close_transaction(self): 
    # Remove listener 
    event.remove(db.session, "after_transaction_end", self.__after_transaction_end_listener) 

    # Roll back the open transaction and return the db connection to 
    # the pool 
    db.session.close() 

    # The app was holding the db connection even after the session was closed. 
    # This caused the db to run out of connections before the tests finished. 
    # Disposing of the engine from each created app handles this. 
    db.get_engine(self.app).dispose() 

    self.trans.rollback() 
    self.connection.invalidate() 
0

siz şu demirbaşlar oluşturabilir pytest kullanıyorsanız: birçok kişi bu iddia edecektir

@pytest.fixture(scope='session') 
def app(): 
    app = create_app('config.TestingConfig') 
    log.info('Initializing Application context.') 

    ctx = app.app_context() 
    ctx.push() 

    yield app 
    log.info('Destroying Application context.') 
    ctx.pop() 

@pytest.fixture(scope='session') 
def db(): 
    log.info('Initializating the database') 

    _db.drop_all() 
    _db.create_all() 

    session = _db.session 
    seed_data_if_not_exists(session) 
    session.commit() 

    yield _db 

    log.info('Destroying the database') 
    session.rollback() 
    #_db.drop_all() #if necessary 

@pytest.fixture(scope='function') 
def session(app, db): 
    log.info("Creating database session") 

    session = db.session 
    session.begin_nested() 

    yield session 

    log.info("Rolling back database session") 
    session.rollback()