[TIP] Learning fixtures in py.test

holger krekel holger at merlinux.eu
Fri Oct 25 02:52:52 PDT 2013


On Thu, Oct 24, 2013 at 17:02 -0400, Paradox wrote:
> I am trying to understand fixtures and how they are used.  I am
> writing tests for my program that interacts with an Sqlite database
> using Sqlalchemy.  I am working on Python 2.7.5 in Ubuntu 13.10.
> 
> My setup_session fixture is:
> 
> =================
> @pytest.fixture (autouse = True)
> def setup_session():
>     db_file = 'database.db'
>     engine = create_engine('sqlite:///' + db_file, echo = True)
>     Base = declarative_base()
>     Session = sessionmaker(bind=engine)
>     session = Session()
>     return session
> ==================

You are using an "autouse" session which means that this fixture
function will be called for every test (no matter if it listed by
argument or not).

Moreover, the default caching scope of fixtures is "function" which
means that ``setup_session`` is called for each test function.
If you rather want to have it invoked only once per test run, you can do:

    @pytest.fixture(autouse=True, scope="session")
    ...

which ensures all tests re-use the same invocation, i.e.
sqlalchemy session instance.

> Then when I try to use that fixture in a test it is something like:
> ==================
> def test_get_id_of_row(setup_session):
>     assert(get_id_of_row('cell known to be in test data')==1)
> ==================

As Brianna points out, something ist missing here.  You don't
use "setup_session" in the assert ...

> I am getting an error:
> ==================
> NameError: global name 'session' is not defined
> ==================

... and in your posted code there is nothing that could raise this error.

> Shouldn't that be taken care of by passing the setup_session fixture
> to the test function?  There is something I don't get about fixtures
> and would appreciate any pointers on where to read to better
> understand, I have read the pytest.org site on fixtures several
> times and it is still not sinking in!

sorry about that.  When pytest runs a test function it looks
at the argument _names_ a test function requires.  And then discovers
the fixture functions by _name_.  If you wanted to use a
`sqlsession`` object you could do::

    @pytest.fixture
    def sqlsession():
        ...  # like in your code
        Session = sessionmaker(bind=engine)
        return Session()

and then in a test:

    def test_sql_something(sqlsession):
        # use sqlsession instance in test

There is no need to have an "autouse" fixture then.  It is fine
to have an auto-use fixture and still receive it as a test function
argument.

If that isn't helping, could you provide some concrete code and the
py.test invocation (at best a minimal example) that doesn't behave like
you want it to?

best,
holger




More information about the testing-in-python mailing list