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!
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.
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.
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
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With