Nov 24

Unit testing in Rails - state of database when test fail

After some code refactoring some tests failed. Ok, that means something in code is wrong and that is great thing to know. Usually it is enough easy to check the test case where the problem occured and fix code in model. However my yesterday problem was a bit complicated because the action that should change create and change objects from dependant models obviously didn't do that in in the way it should. It would be easiest method to find where problem is to check the state of database just before test failed.

After some code refactoring some tests failed. Ok, that means something in code is wrong and that is great thing to know. Usually it is enough easy to check the test case where the problem occured and fix code in model. However my yesterday problem was a bit complicated because the action that should change create and change objects from dependant models obviously didn't do that in in the way it should. It would be easiest method to find where problem is to check the state of database just before test failed.

Here are few facts about unit testing that I learned after few hours trying to find way to see whats in the database when test failed:

  • before every unit test method is run specified fixture file would be loaded into table(s) after deleting all rows in these table(s)
  • all exceptions would be handled by TestCase except PASSTHROUGH_EXCEPTIONS [NoMemoryError, SignalException, Interrupt, SystemExit]
  • after any test method is finished or failed teardown() method would be called

So, I guessed it would be easiest to override teardown() to do nothing, exit from test method with exit! and inspect what’s in database. But, no, database was unchanged, I even try to sleep thread and watch database.

Nothing worked. After digging deeper in code solution come out – Transactional fixtures:

Transactional fixtures accelerate your tests by wrapping each test method in a transaction that’s rolled back on completion.

So the solution is to turn off transactional fixtures by adding following code in test:

self.use_transactional_fixtures = false

These way you can check what exactly is in the database when concrete test method failed or is about to fail. Note: transactional fixtures are much faster so it is preferred to have them enabled unless you need to turn off transactions.

Tags: