Hi,
Just a quick followup message. Thanks again Andi for sharing your idea and
thanks Michael for the idea of using the testapp environment to pass in
session and/or request transaction manager. Your suggestions have really
helped a Python and Pyramid newbie! Fingers crossed, I think I have managed
to get it working now with some tweaking here and there....bit pushed for
time so quickly pasting the fixtures, request method and sample test.
Here are the pytest fixtures.....
@pytest.fixture(scope="session")
def settings():
""" Return a dictionary of application settings defined in test.ini,
including expanded environment variables.
:return: Dictionary of application settings defined in test.ini.
"""
testconfigfile = project_path(pytest.config.rootdir.strpath, 'test.ini')
settings = get_appsettings(testconfigfile, name='main')
settings = load_environment(testconfigfile, settings)
conf = {'global_config': {'__file__': testconfigfile}}
settings.update(conf)
return settings
@pytest.fixture(scope="function")
def testapp(settings, session):
""" Wrap `webtest.TestApp` request within a doomed transaction that aborts
when a test completes.
Attempts to commit will raise a `DoomedTransaction` exception. Doomed
transactions can only be aborted.
The test app instance is initialised with environment tm.active set to True
to instruct pyramid_tm to bypass
creating transaction for request.
:param settings: dictionary of application settings contained within
`test.ini`.
:param session: SQLAlchemy session.
:return: webtest.TestApp object.
"""
testing.setUp()
log.info("testapp fixture :: starting a doomed transaction")
with transaction.manager as tx:
tx.doom()
from plantoeducate_data.models import set_tm_session
app = main(**settings)
testapp = webtest.TestApp(app, extra_environ={'db.session': session,
'tm.active': True})
set_tm_session(session, transaction.manager)
yield testapp
log.info("testapp fixture :: aborting transaction")
tx.abort()
testing.tearDown()
@pytest.fixture(scope="session")
def session(settings):
""" Return a SQLAlchemy session for the database referenced by
`sqlalchemy.url` within test.ini file.
When tests have been run the session is closed and the associated engine is
disposed.
:param settings: dictionary of application settings contained within
`test.ini`.
:return: SQLAlchemy session object.
"""
engine = get_engine(settings, prefix='sqlalchemy.')
factory = get_session_factory(engine)
Base.metadata.create_all(engine)
session = factory()
yield session
session.close()
engine.dispose()
and here is the request method.....
def set_tm_session(session, transaction_manager):
zope.sqlalchemy.register(session, transaction_manager=transaction_manager)
return session
def includeme(config):
...
# use pyramid_tm to hook the transaction lifecycle to the request
config.include('pyramid_tm')
session_factory = get_session_factory(get_engine(filtered_settings))
config.registry['dbsession_factory'] = session_factory
def add_tm_session(request):
""" Request method that returns a SQLAlchemy session for a request.
The SQLAlchemy session is managed by a Zope transaction, unless the request
has been generated from a
webtest.TestApp instance for functional testing. In this case:
- Inspect request.environ dictionary for the SQLAlchemy session referenced
by key db.session. Remove the
session from the request's environment dictionary and return the
session.
- Use the session factory to generate and return a new SQLAlchemy session
if there is no entry for db.session
in the request environment dictionary.
When functional testing it is the responsibility of the test client to
configure the Zope transaction
manager for the SQLAlchemy session. For example:
with transaction.manager as tx:
set_tm_session(session, tx)
The webtest.TestApp instance should configure the environment dictionary as
follows:
`testapp = webtest.TestApp(app, extra_environ={'db.session': session,
'tm.active': True})`
Setting tm.active to True causes the pyramid_tm tween to bypass generating
a transaction for the SQLAlchemy
session on the request.
:param request: Pyramid Request instance
:return: SQLAlchemy session.
"""
if 'paste.testing' in request.environ and request.environ['paste.testing']
is True:
if 'db.session' in request.environ:# and 'db.tm' in request.environ:
dbsession = request.environ['db.session']
del request.environ['db.session']
return dbsession
#return set_tm_session(request.environ['db.session'],
request.environ['db.tm'])
else:
return session_factory()
return get_tm_session(session_factory, request.tm)w
config.add_request_method(add_tm_session, 'dbsession', reify = True)
and a sample test fixture.....
def test_filter_documents_feedback(self, testapp, documents):
res = testapp.get('/documents/templates/2', status=200)
log.info("test_filter_documents_feedback :: completed filter request")
expected_feedback_templates_count = 1
expected_templates_count = 2
assert(len(res.json['data']) == expected_feedback_templates_count)
assert(documents.query(DocumentTemplateModel).count() ==
expected_templates_count)
The *testapp* fixture provides access to a *webtest.TestApp *instance
wrapped by a transaction. The *webtest.TestApp* instance stores a
SQLAlchemy session in the extra_environ dict referenced by key db.session
which is available for the pyramid request method to grab and make
available on each request.
The documents fixture populates some data in the session and then yields
the session to the test.
Thanks again!!!
Kind regards
dcs3spp
--
You received this message because you are subscribed to the Google Groups
"pylons-discuss" 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].
To view this discussion on the web visit
https://groups.google.com/d/msgid/pylons-discuss/d61de1b6-1da0-4505-ac51-5f7b72c619b9%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.