Rails: Testing Named Scopes with Rspec

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



Leave a reply



Submit