Rails: Testing named scopes with RSpec
The creator of RSpec has recently blogged he thinks Validations are behavior, associations are structure. In other words he finds that associations (and scopes) should not nessesarily be tested directly. Tests for these will follow from the behavior you want.
In other words, current wisdom is that there is no need to test each scope directly, since you will cover these associations by testing the behavior of your application.
How to write tests for active record scopes?
Assuming that you have the appropriate fixtures setup, I usually run a query where I expect results from the scope, and one where I don't. For example:
describe '#published' do
it "returns a published post" do
expect(Post.published.count).to be(1)
# or inspect to see if it's published, but that's a bit redundant
end
it "does not return unpublished posts" do
expect(Post.published).to_not include(Post.where("status = 0"))
end
end
Rails –Testing named scopes: test scope results or scope configuration?
I think you have described the problem very well, and that the best answer, in my opinion is - it depends.
If your scope is trivial, run-of-the-mill where
, with some order
, etc. there is no real need to test ActiveRecord
or the database to make sure they work properly - you can safely assume that they have been correctly implemented, and simply test the structure you expect.
If, on the other hand, your scope (or any query) is compound, or uses advanced features in a complex configuration, I believe that setting up tests that assert its behavior, by using a real live database (which is installed locally, with a small custom-tailored data set) can go a long way in assuring you that your code works.
It will also help you, if and when you decide to change strategies (use that cool new mysql
feature, or porting to postgresql
), to refactor safely, by checking that the functionality is robust.
This is a much better way than to simply verify the the SQL
string is what you typed there...
Rspec: testing the response of a model scope
Try to use let!
, #to_a
and match_array
:
let(:today) { Date.today }
let!(:account1) { create(:account, last_seen: today) }
let!(:account2) { create(:account, last_seen: today - 4.days) }
let!(:account3) { create(:account, last_seen: today - 10.days) }
subject { Account.seen_between(today - 14.days, today - 2.days).to_a }
it { is_expected.to match_array [account2, account3] }
P.S. With match_array
you need no extra expect(...).not_to include
.
How to test scopes?
David Chelimsky (Rspec's creator) offered up the following example in the Rspec Google Group:
describe User, ".admins" do
it "includes users with admin flag" do
admin = User.create! :admin => true
User.admin.should include(admin)
end
it "excludes users without admin flag" do
non_admin = User.create! :admin => false
User.admin.should_not include(non_admin)
end
end
class User < ActiveRecord::Base
named_scope :admins, :conditions => {:admin => true}
end
It's obviously not the same example as yours, but it should give you an idea of how to do it. The relevant thread for context is here: http://groups.google.com/group/rspec/browse_thread/thread/6706c3f2cceef97f
how to write rspec test for scope in model
You can test this kind of thing by making a collection, and then doing
expect(Mymodel.scope).to match_array(expected_collection)
Using RSpec to test active record scope that uses the includes method
After positing to the RSpec users mailing list and reading more about speccing in general, I ultimately came to the realization that this isn't worth a unit test. The :includes directive is well tested in rails and the overhead of testing that simple line is higher than the risk associated with it failing or being removed by another developer - at least in my case.
What I really care about is performance of the application. Speccing performance would be a lot more productive than jumping through hoops to unit test this line.
Related Topics
Ruby Convert Array into Function Arguments
Ruby: How to Concatenate Array of Arrays into One
What Are the Differences Between Rbenv, Rvm, and Chruby
Ruby: Create a String from Bytes
How to Check to See If a File Exists (On the Remote Server) in Capistrano
Check If a Hash's Keys Include All of a Set of Keys
How to Run Rake Tasks Within My Rails Application
Why Does Ruby "Script/Generate" Return "No Such File or Directory"
How to Reference Global Variables and Class Variables
Which Gem Support Import/Export to Xlsx File in Ruby
Ruby - Elegantly Convert Variable to an Array If Not an Array Already
Add Element to an Array If It's Not There Already
Attr_Accessor on Class Variables
Ruby: Module, Require and Include
Ruby Classes Within Classes (Or Modules Within Modules)
Nicely Formatting Output to Console, Specifying Number of Tabs