I've been struggling with this for a few days now, and I've tried a whole
slew of different approaches, but I'm just missing something.
I started with the example
at
http://docs.sqlalchemy.org/en/latest/orm/session_transaction.html#joining-a-session-into-an-external-transaction-such-as-for-test-suites
and have been trying variations on it to suit my goals.
We have a webapp which, in simplest form, could be represented as this:
# in the db setup file
dsn = 'mysql://...t'
engine = create_engine(dsn)
session_factory = sessionmaker(bind=engine)
scoped = scoped_session(session_factory)
# the app
class Webapp(object):
def dispatch(self, name):
view = getattr(self, name)
session = scoped()
try:
rsp = view()
session.commit()
return rsp
except:
session.rollback()
return 'error'
finally:
session.close()
pass
# the views files
def add_user(self, session):
user = User(username='test')
session = scoped()
session.add(user)
session.flush()
return 'user %s' % user.id
The app uses commit, rollback, and close on a scoped session.
I'd like to know how to adjust the example at the above URL so the test is
able to "enclose" the webapp, so the calls to sessionmaker, and all
operation that occur within the webapp, are within the scope of the test
transaction, so everything that happens in the app can be rolled back at
the end of the test. The example at the url acquires a connection, and
binds the session to the connection, and I'm not sure how to force the
sessionmaker to work with that. Could 'scopefunc' be used to somehow force
the returned session to be within the context of the transaction?
There is also fixture loading code, which starts by acquiring a session
from the scoped_session, adding fixtures, then committing. A simple example
could be this function:
def load_fixture(username):
session = scoped()
session.add(User(username=username))
session.commit()
I'd like to use this in unittests, and have it rolled back along with the
transaction.
I attached a full (nonworking) example, can you tell me what I am doing
wrong? Is this even possible with a scope session, or is this sort of
testing limited to to sessions bound to connections? Would I need to
rewrite the session acquisition method to return a globally stored
connection-bound session before defaulting to the scoped (engine-bound)
session?
An example I saw
at
https://web.archive.org/web/20140419235219/http://sontek.net/blog/detail/writing-tests-for-pyramid-and-sqlalchemy
seems to indicate that person overwrote the app session from within the
unittest, to ensure the app used that session. Is that the approach I would
need to take?
--
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.
from sqlalchemy import *
from sqlalchemy import event
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import scoped_session
from sqlalchemy.orm import sessionmaker
from sqlalchemy import create_engine
import unittest
dsn = 'mysql://...'
engine = create_engine(dsn)
session_factory = sessionmaker(bind=engine)
scoped = scoped_session(session_factory)
Base = declarative_base()
class User(Base):
__tablename__ = 'test_users'
username = Column(String(50), primary_key=True)
def __repr__(self):
return "'%s'" % self.username
class Webapp(object):
def dispatch(self, name):
# in the real app, views are spread out over the fs
# and are looked up via a cached url configuration,
# they are not attributes of the base app
view = getattr(self, name)
session = scoped()
try:
rsp = view()
session.commit()
return rsp
except:
session.rollback()
return 'error'
finally:
session.close()
pass
def add_user(self):
session = scoped()
user = User(username='app')
session.add(user)
session.flush()
return 'user %s' % user.username
def view_user(self):
session = scoped()
user = session.query(User).get('setup')
return 'user %s' % user.username
def delete_user(self):
session = scoped()
user = session.query(User).get('setup')
session.delete(user)
session.flush()
return 'deleted'
def load_fixture(username):
session = scoped()
session.add(User(username=username))
session.commit()
def setUpModule():
print 'setup module'
Base.metadata.bind = engine
Base.metadata.drop_all()
Base.metadata.create_all()
def tearDownModule():
print 'teardown module'
class SomeTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
print 'setup class'
cls.app = Webapp()
cls.session = scoped()
cls.trans1 = cls.session.begin_nested()
load_fixture('setupclass')
print 'post-setupclass users:', cls.session.query(User).all()
@classmethod
def tearDownClass(cls):
print 'pre-teardown class users:', cls.session.query(User).all()
cls.trans1.rollback()
cls.session.close()
print 'post-teardown class users:', cls.session.query(User).all()
def setUp(self):
print '\npre-setup users:', self.session.query(User).all()
self.trans2 = self.session.begin_nested()
load_fixture('setup')
print 'post-setup users:', self.session.query(User).all()
def tearDown(self):
print 'pre-teardown users:', self.session.query(User).all()
self.trans2.rollback()
print 'post-teardown users:', self.session.query(User).all()
#def test_view(self):
# rsp = self.app.dispatch('view_user')
# print rsp
def test_add(self):
rsp = self.app.dispatch('add_user')
print rsp
#def test_delete(self):
# rsp = self.app.dispatch('delete_user')
# print rsp
if __name__ == "__main__":
unittest.main()