I try to test query object.

The controller looks like this:

class MoviesController < ApplicationController before_action :find_movie, except: [:index] def index @movies = FindMovies.new(Movie.all).call(movie_params) end private def movie_params params.permit(:recommendation, :page, :current_user) params.merge!(current_user: current_user) end 

Query object itself:

 class FindMovies attr_accessor :initial_scope def initialize(initial_scope) @initial_scope = initial_scope end def call(params) scoped = @initial_scope if params[:recommendation] == 'recommended' scoped = recommended(scoped, params[:current_user]) elsif params[:recommendation] == 'not recommended' scoped = not_recommended(scoped, params[:current_user]) end scoped = paginate(scoped, params[:page]) [scoped, params[:recommendation] || 'all'] end private def recommended(scoped, current_user) Movie.where(id: current_user.votes.where(value: 1).pluck(:movie_id)) end def not_recommended(scoped, current_user) Movie.where(id: current_user.votes.where(value: -1).pluck(:movie_id)) end def paginate(scoped, page) scoped.order(:created_at).page(page).per(10) end end 

Test:

 require 'rails_helper' describe 'Query tests' do let(:user) { create(:user) } let(:movie) { create(:movie) } let(:another_movie) { create(:movie, title: 'Gladiator', tmdb_id: 98) } let(:vote) { create(:vote, user_id: user.id, movie_id: movie.id) } let(:another_vote) { create(:vote, user_id: user.id, movie_id: another_movie.id, value: -1) } context 'find move' do it 'returns all' do movies = FindMovies.new(Movie.all).call({ current_user: user }) expect(movies.count).to eq(2) puts user.inspect expect(movies[1]).to eq('all') end it 'returns recommended' do movies = FindMovies.new(Movie.all).call({ current_user: user, recommendation: 'recommended' }) puts user.inspect expect(movies[1]).to eq('recommended') end it 'returns not recommended' do movies = FindMovies.new(Movie.all).call({ current_user: user, recommendation: 'not recommended' }) puts user.inspect expect(movies[1]).to eq('not recommended') end end end 

For some reason, in each test user is created again? When should it be created once in let, and then simply assigned to the current_user parameter?

    1 answer 1

    Insulation for

    From the documentation for let (bold important part):

    Use let to define a memoized helper method. But not across examples .

    Use let to define a helper memoing method. The return value will be cached for calls within the sample, but not for different examples .

    What for?

    RSpec, unless it is explicitly requested, tries to isolate the execution of individual examples as much as possible so that they minimally influence each other and remain predictable when performed in any order and with any subset.

    Since in each example you can potentially change the object that is returned by the let method, for this purpose it is safer to recreate this object for each example.

    See also the relevant item Better Specs .


    If you really need the object in several examples to be the same, use the before(:all) hook and instance variables in the a- @thing :

     require "rspec/expectations" class Thing def widgets @widgets ||= [] end end describe Thing do before(:all) do @thing = Thing.new end describe "initialized in before(:all)" do it "has 0 widgets" do @thing.should have(0).widgets end it "can get accept new widgets" do @thing.widgets << Object.new end it "shares state across examples" do @thing.should have(1).widgets end end end