Rails –Testing named scopes: test scope results or scope configuration?
Asked Answered
H

1

30

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.

Harpsichord answered 7/4, 2014 at 2:29 Comment(0)
T
23

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

Tung answered 7/4, 2014 at 19:55 Comment(3)
+1 Thanks for the thoughtful answer. Just to clarify, my intention with the results-based spec was never to test ActiveRecord itself, but the User.admins interface: I don't care what goes on under the covers of the interface (obviously in this case, as with all Rails conventional scopes, it uses ActiveRecord), just that I get a set of results back that includes/excludes users as per how I've defined an admin user to be. I agree with you regarding testing for results on advanced queries, but I wonder how advanced is "advanced", where it becomes risky to only test on scope configuration...Harpsichord
I would say that if you resorted to writing an SQL in your code - ActiveRecord functionality only guarantees that that SQL will be run, of course testing that the SQL is run will not be sufficient, and you'd want to test its results. As for how compound should a scope be (without resorting to SQL) before it is called "advanced", I guess your gut is as good as mine, but I think that you'd know it when you see it...Tung
Thanks very much for answering, Uri. Looks like everyone pretty much agrees with you, so please enjoy your bonus internet points :-) I'm going to leave the question open for a little bit longer in case someone posts an answer with some anecdotes of their own scope testing procedures etc. Otherwise, I'll accept this and close out the question.Harpsichord

© 2022 - 2024 — McMap. All rights reserved.