Rolling back all changes between unit tests

608 views
Skip to first unread message

Ib Lundgren

unread,
Jul 23, 2013, 12:58:51 PM7/23/13
to sqlal...@googlegroups.com
Hey all,

I'd like to have a clean DB between tests, one approach that works is to drop tables and recreate fixtures. This can be quite slow and I'd rather have something more lean. 

If possible I'd like to create a snapshot before each test and rollback to the snapshot after each test. From browsing the docs it seems like SQLAlchemy might be able to achieve this using nested transactions or subtransactions. FWIW I am using Postgres 9.1+.

I had a quick go at this and ended up with something similar to

# my_db.py
session = .... # setup connect & session to postgres

# my_app.py
from .my_db import session

def add_stuff():
    session.add(stuff)
    session.commit()

# test.py
from .my_db import session
from .my_app import add_stuff

class MyTest(unittest.TestCase):

    def setUp(self):
         session.begin_nested()

    def tearDown(self):
         session.rollback()

    def test_app(self):
         add_stuff()

but that does not work. The commit in add_stuff is not reverted by the rollback in tearDown. Am I going in the right direction?

Cheers!

Pau Tallada

unread,
Jul 24, 2013, 3:31:28 AM7/24/13
to sqlal...@googlegroups.com
Hi!

A successful commit cannot be rolled back.
Do not use commit. Use session.flush instead, then you could use rollback to revert changes.

Cheers,

Pau.

2013/7/23 Ib Lundgren <ib.lu...@gmail.com>

--
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 sqlalchemy+...@googlegroups.com.
To post to this group, send email to sqlal...@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/groups/opt_out.
 
 



--
----------------------------------
Pau Tallada Crespí
Dep. d'Astrofísica i Cosmologia
Port d'Informació Científica (PIC)
----------------------------------

Ladislav Lenart

unread,
Jul 24, 2013, 3:39:48 AM7/24/13
to sqlal...@googlegroups.com, Ib Lundgren
Hello.

I am not familiar with the usage of nested transactions, though I am pretty sure
what you want is possible.

I would like to suggest a simpler approach. If you implement all your functions
without commit and move the commit to one place (e.g. to the end of a web
request processing), you can write tests like this:

> *# my_db.py*
> session = .... # setup connect & session to postgres
>
> *# my_app.py*
> from .my_db import session
>
> def add_stuff():
> session.add(stuff)
>
> *# test.py*
> from .my_db import session
> from .my_app import add_stuff
>
> class MyTest(unittest.TestCase):
>
> def tearDown(self):
> session.rollback()
>
> def test_app(self):
> add_stuff()
> session.flush()
> # assert against db

Recap:
* Do not use session.commit() in your code. Move it to one place outside the app
logic.
* Call session.flush() in your test whenever you want to assert something
against the database.
* Use rollback() at the end of a unit test.


HTH,

Ladislav Lenart


On 23.7.2013 18:58, Ib Lundgren wrote:
> Hey all,
>
> I'd like to have a clean DB between tests, one approach that works is to drop
> tables and recreate fixtures. This can be quite slow and I'd rather have
> something more lean.
>
> If possible I'd like to create a snapshot before each test and rollback to the
> snapshot after each test. From browsing the docs it seems like SQLAlchemy might
> be able to achieve this using nested transactions or subtransactions. FWIW I am
> using Postgres 9.1+.
>
> I had a quick go at this and ended up with something similar to
>
> *# my_db.py*
> session = .... # setup connect & session to postgres
>
> *# my_app.py*
> from .my_db import session
>
> def add_stuff():
> session.add(stuff)
> session.commit()
>
> *# test.py*
> from .my_db import session
> from .my_app import add_stuff
>
> class MyTest(unittest.TestCase):
>
> def setUp(self):
> session.begin_nested()
>
> def tearDown(self):
> session.rollback()
>
> def test_app(self):
> add_stuff()
>
> but that does not work. The commit in add_stuff is not reverted by the rollback
> in tearDown. Am I going in the right direction?
>
> Cheers!
>
Reply all
Reply to author
Forward
0 new messages