egervari
egervari

Reputation: 22512

Where do I put my database query tests in rails?

I am coming from a Spring/hibernate background. I have noticed that Rails has no dao and service layers. This really speeds up development, but I don't know where to put my tests sometimes.

Right now, I've been putting my model methods and validation tests in the main model spec. This file is already fairly large.

Where is the 'standard' place to test queries? I can imagine myself making a lot of fixtures/dummy data to make sure my queries are working as expected (probably an even better idea since I am new to rails). These are not really needed for the basic model logic and validation tests.

If you could offer some advice as to where put these tests, the best approach to testing queries using rails (especially ones with multiple joins!), and maybe some basic guidelines of how it might different from doing it with DBunit/spring/hibernate, that would be great.

Thanks!

Upvotes: 7

Views: 3561

Answers (3)

oma
oma

Reputation: 40770

I used to work with hibernate too. The ActiveRecord way is very different from hibernate. You need to set your mind free, for better or for worse. In java and Hibernate you often have the aggregate root and the object graph. Generally, both the object graphs and code base are smaller in ruby somehow too. I don't know your particular case, so I'll tread carefully, but I warn you to try fit ruby, and rails, to your java habits.

You may use custom directories with rspec to organize in a way that makes sense for you and your team.

#spec/queries/my_custom_search_spec.rb

require 'spec_helper'
describe MyModel do
  it "should do this query and return X" do
     subject.some_defined_scope_search.should == "something"
  end
end

and you may have subdirectories, automatically getting picked up by rspec, like spec/models/account/..

The spec will automatically be picked up by rake spec or rspec spec. I just wrote a simple example above, as I don't know your case. Do you define scopes with queries, or define specialized methods?

I strongly recommend abandoning the fixtures (same as the inserts - anti pattern, to me) for something more refactorable, like factories. I like factory_girl. It let's your app evolve in a more agile manner, IMO.

EDIT: adding my spec_helper.rb with settings for enable/disable automatic cleanup

RSpec.configure do |config|
  require 'database_cleaner'
  config.add_setting :skip_database_clean
  config.skip_database_clean = false
  config.before(:suite) do
    DatabaseCleaner.strategy = :truncation
  end

  config.before(:each) do
  end

  config.after(:each) do
    MongoMapper.database.collections.each(&:remove)
    DatabaseCleaner.clean unless config.skip_database_clean
  end

I add the variable skip_database_clean so that I can enable/disable the autocleanup after each spec (each "it").

  before :all do
    @an_object = some_expensive_test_buildup
    RSpec.configuration.skip_database_clean = true
  end
  after :all do
    RSpec.configuration.skip_database_clean = false
    DatabaseCleaner.clean
  end

Upvotes: 4

Mike Tunnicliffe
Mike Tunnicliffe

Reputation: 10772

Rails uses Arel to generate the SQL for your database queries based on relationships you define in Ruby code through the Rails ActiveRecord associations API (assuming you are using ActiveRecord as your ORM, it is the default). You can write your own SQL if you think you can improve upon what is generated automatically (which you can see in the log files).

Usually you will invoke these queries (whether written manually or automatically) through a method call on the model. For example, @author.books or @author.readers; these could embody a query that has joins.

I'm not sure about hand-written queries, but generated queries are usually built with scopes that once fully constructed are realized when the results are requested. For example, @author.books.order('price').limit(10). You can define your own custom scopes.

I would test the correctness of your custom queries or scopes in the unit test for the model in the case where they are integral to the working of the model. For example, @author.popular_books might be a custom scope defined on your model, and you can write a unit test for your Author model to ensure that it returns the expected results for some known test data.

Upvotes: 1

Jesse Wolgamott
Jesse Wolgamott

Reputation: 40277

If you use normal rails ORM, then you don't create queries, and you don't need to test the data access.

If you do start to write custom SQL queries, then I recommend you use rspec and test the behavior of your objects after you execute the queries.

Upvotes: 0

Related Questions