Question

How should Rails named scopes be tested? Do you test the results returned from a scope, or that your query is configured correctly?

If I have a User class with an .admins method like:

class User < ActiveRecord::Base
  def self.admins
    where(admin: true)
  end
end

I would probably spec to ensure I get the results I expect:

describe '.admins' do
  let(:admin) { create(:user, admin: true) }
  let(:non_admin) { create(:user, admin: false) }
  let(:admins) { User.admins }

  it 'returns admin users' do
    expect(admins).to include(admin)
    expect(admins).to_not include(non_admin)
  end
end

I know that this incurs hits to the database, but I didn't really see any other choice if I wanted to test the scope's behaviour.

However, recently I've seen scopes being specced by confirming that they're configured correctly, rather than on the result set returned. For this example, something like:

describe '.admins' do
  let(:query) { User.admins }
  let(:filter) { query.where_values_hash.symbolize_keys }
  let(:admin_filter) { { admin: true } }

  it 'filters for admin users' do
    expect(filter).to eq(admin_filter) # or some other similar assertion
  end
end

Testing the direct innards of a query like this hadn't really occurred to me before, and on face value it is appealing to me since it doesn't touch the database, so no speed hit incurred.

However, it makes me uneasy because:

  • it's making a black-box test grey(er)
  • I have to make the assumption that because something is configured a certain way, I'll get the results that my business logic requires

The example I've used is so trivial that perhaps I'd be okay with just testing the configuration, but:

  • where do you draw the line and say 'the content of this named scope is too complex and requires result confirmation tests over and above just scope configuration testing'? Does that line even exist or should it?
  • Is there a legitimate/well-accepted/'best practice' (sorry) way to test named scopes without touching the database, or at least touching it minimally, or is it just unavoidable?
  • Do you use either of the above ways to test your scopes, or some other method entirely?

This question(s) is a bit similar to Testing named scopes with RSpec, but I couldn't seem to find answers/opinions about testing scope results vs scope configuration.

Was it helpful?

Solution

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...

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top