Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 688
egervari Avatar asked May 02 '11 21:05

egervari


People also ask

How do I run a test file in rails?

We can run all of our tests at once by using the bin/rails test command. Or we can run a single test file by passing the bin/rails test command the filename containing the test cases. This will run all test methods from the test case.

How do you run a Minitest in rails?

To run a Minitest test, the only setup you really need is to require the autorun file at the beginning of a test file: require 'minitest/autorun' . This is good if you'd like to keep the code small. A better way to get started with Minitest is to have Bundler create a template project for you.


2 Answers

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
like image 172
oma Avatar answered Sep 20 '22 07:09

oma


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.

like image 25
Mike Tunnicliffe Avatar answered Sep 19 '22 07:09

Mike Tunnicliffe