Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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.

like image 651
Paul Fioravanti Avatar asked Apr 07 '14 02:04

Paul Fioravanti


People also ask

How does scope work in Rails?

Scopes are custom queries that you define inside your Rails models with the scope method. Every scope takes two arguments: A name, which you use to call this scope in your code. A lambda, which implements the query.

Why do we use scope in Rails?

Scopes are used to assign complex ActiveRecord queries into customized methods using Ruby on Rails. Inside your models, you can define a scope as a new method that returns a lambda function for calling queries you're probably used to using inside your controllers.

What is scope method in Ruby?

Scope defines where in a program a variable is accessible. Ruby has four types of variable scope, local, global, instance and class. In addition, Ruby has one constant type. Each variable type is declared by using a special character at the start of the variable name as outlined in the following table.


1 Answers

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

like image 186
Uri Agassi Avatar answered Sep 20 '22 15:09

Uri Agassi