Non-rails unit tests don't hit the db but Rails unit tests do

Generally when unit testing in non-Rails apps, we never write unit tests which hit a database. If we're forced to, we keep them to a minimum, treat them as a symptom of bad design and do our best to refactor them away over time. This is because you should be able to create and use models independently of your database - otherwise your code is implicitly tied to your db schema, something you want to avoid.

Thing is, this isn't true for Rails because of the neat one-to-one mapping of a table to a domain object.

Just an observation.

4 comments:

Aslak Helles√ły said...

RSpec, with its support for one-layer testing of Rails code makes it easier to test controllers, views and helpers independently of models (and the database).

I agree with you in principle that it's healthy to try and keep the (domain) model agnostic of the database - especially because it speeds up testing.

You said one thing that made me curious:

"This is because you should be able to create and use models independently of your database - otherwise your code is implicitly tied to your db schema, something you want to avoid."

I would be interested in hearing why you think this dependency on a database schema should be avoided.

Sidu said...

I guess my thinking is coloured by the kind of work we do. On most client projects, we end up having little or no control over the db schema (you'd know more about this than I, Aslak :-D). Given this constraint, it seems wiser to ensure that the schema was abstracted away from the model so that schema changes didn't directly affect them.
Have I missed something?

BlueFish said...

I sort of agree i think business logic code should go no place near the DB but what about data tiers and data dictionary do you not have boundary tests for these ?

I regularly write TTD driven data suits with there own database tear down and setup scripts.

Sidu said...

bluefish,
One way of figuring out whether you are on the right path is by answering the question, "Which unit are you testing with your unit tests?"
In the case of Rails, you end up implicitly testing much of ActiveRecord as well, something that is not your responsibility to test. This also means that you are no longer testing 'units' of code, but rather a combination of your code and a slice of AR. Changes to AR can now affect the outcome of your tests.

aslak,
Dan Manges has done a much better job - see Rails: UnitRecord - Test without the Database