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.

Reply via email to