Search code examples
pythonsessionflaskpython-behave

Access Flask session in behave steps


I'm using Flask and behave, following the instructions here.

I'm accessing pages using the Flask test client (rather than through a browser via something like Selenium). For example, calling get on the test client to get a response.

I'd like to access Flask session data in my steps. There are various techniques documented on the Testing Flask Applications page about accessing context and sessions, but I can't see that any of them are quite what I need when using behave, in particular as I'll be accessing the page in one step and then wanting to retrieve session in another.

My environment.py looks like this:

from my_app import app


def before_scenario(context, scenario):
    app.testing = True
    # load the test config to ensure e.g. right database used
    app.config.from_object('parameters.test')
    context.client = app.test_client()


def after_scenario(context, scenario):
    pass

Solution

  • The Flask testing technique that came closest to what I needed was this one:

    with app.test_client() as c:
        rv = c.get('/')
        assert flask.session['foo'] == 42
    

    The problem I had with this is that I needed to make the get request in one step and check the session later in another - i.e. the code was in different functions, so couldn't all be wrapped in the with block.

    Reading sessions

    The with statement is essentially syntactic sugar for a pattern similar to try/finally (see link), so I could break this down a bit, giving me the following environment.py:

    from my_app import app
    
    
    def before_scenario(context, scenario):
        # all the code I had before still here
        # ...
        # and this new line:
        context.client.__enter__()
    
    
    def after_scenario(context, scenario):
        # the exit code doesn't actually use its parameters, so providing None is fine
        context.client.__exit__(None, None, None)
    

    In my steps, I can now do from flask import session and access session as I would in my normal application. You can access request in the same way.

    Writing sessions

    As the Flask testing page says, this approach "does not make it possible to also modify the session or to access the session before a request was fired."

    If you need to do that, you need to extend the pattern slightly further. First (in before_scenario), assign the return value from __enter__() to a variable you can access later:

    context.session = context.client.__enter__()
    

    then, in your steps, you can do this:

    with context.session.session_transaction() as sess:
        sess['key here'] = some_value
    

    This is the second pattern described in the section linked to at the start of my answer. The only modification is that you need to store the return value from __enter__() since you're not using a with statement.