Database Cleaner by default

In most new projects I had to use database_cleaner because transaction boundaries are often too restrictive. Should it be in by default?

I would vote absolutely not. Transactions as a boundary for testing are important, and save for functional/external tests where I can see an argument (distinct http requests where you can’t rely on a transaction) there’s no excuse for violating this.

Rails tests are often slow enough anyway, if AR was better at transactions and transactional safety in general then we wouldn’t have to rely so much on the database.

If you use database-cleaner then you can’t paralleize tests as much and your test suite just grows slower and slower.

8 Likes

Replying to myself to say that the best/fastest experience I’ve ever had testing and maintaining has been using rom-rb and not activerecord and a “repository pattern” with “functionally isolated” changesets, so you can test “this operation should change these things”, and defer that to the database layer, and never have to do any external IO in tests because the design of rom-rb fits better than active record for my mental model.

Could you please provide some examples?

In most new projects I had to use database_cleaner

I have an opposite experience: I’m dropping database_cleaner from every project I touch, because it’s not needed.

6 Likes

I find that the moment you need to test after_commit logic the usual rollback-based cleaning does not suffice. Personally I encounter after_commit quite often, for example, to persist denormalised copies of records in other (NoSQL) systems.

Is this because of capybara tests? On the latest rails versions with system tests you don’t need to use database_cleaner anymore.

1 Like

I’m glad that rom-rb works better for your mental model and I’m glad you’re able to use it.

There are a lot of different styles of writing Rails code (see also, the comments about after_commit) and in this forum, I’d like us to not be prescriptive about any particular style.

Rails became smart enough to invoke after_commit callbacks in transactional tests since Rails 5. Prior to that we had test_after_commit gem.

There are some scenarios when transactions do not work, for example:

  • External services using the same database (Sphinx search engine, for instance).
  • Libraries explicitly checking for open transactions in their internals w/o taking into account transaction tests (e.g., identity_cache).

I don’t think these scenarios too popular to add yet another default gem to Rails.

2 Likes