2010-10-30 15 views
14

Sto provando a testare un ambito che ho basato su una catena di altri ambiti. ("public_stream" di seguito).Stubbing Chained Queries in Rails 3 e Rspec

scope :public, where("entries.privacy = 'public'") 
scope :completed, where("entries.observation <> '' AND entries.application <> ''") 
scope :without_user, lambda { |user| where("entries.user_id <> ?", user.id) } 
scope :public_stream, lambda { |user| public.completed.without_user(user).limit(15) } 

Utilizzando un test come questo:

it "should use the public, without_user, completed, and limit scopes" do 
     @chain = mock(ActiveRecord::Relation) 
     Entry.should_receive(:public).and_return(@chain) 
     @chain.should_receive(:without_user).with(@user).and_return(@chain) 
     @chain.should_receive(:completed).and_return(@chain) 
     @chain.should_receive(:limit).with(15).and_return(Factory(:entry)) 

     Entry.public_stream(@user) 
    end 

Tuttavia, continuo a ricevere questo errore:

Failure/Error: Entry.public_stream(@user) 
undefined method `includes_values' for #<Entry:0xd7b7c0> 

Sembra includes_values ​​è una variabile del ActiveRecord istanza :: oggetto Relation , ma quando provo a fermarlo, continuo a ricevere lo stesso errore. Mi stavo chiedendo se qualcuno avesse esperienza con le nuove query incatenate di Rails 3? Riesco a trovare un sacco di discussioni su hash find 2.x, ma nulla su come testare ciò che è attuale.

+1

Per curiosità, funziona se non si utilizza 'public'?Esiste un conflitto tra il nome dell'ambito e la parola chiave 'public' Ruby. Non sono sicuro che questo sia il problema, ma sarebbe interessante sapere se nella catena questo test fallisce. –

+0

Gli ambiti sono direttamente correlati al database, quindi non è necessario testarli separatamente. Basta creare alcuni record reali e testare cosa restituisce la query. – RocketR

risposta

20

Uso lo standard stub_chain di rspec per questo. Potreste essere in grado di usare qualcosa come:

some_model.rb

scope :uninteresting, :conditions => ["category = 'bad'"], 
         :order => "created_at DESC" 

controller

@some_models = SomeModel.uninteresting.where(:something_else => true) 

spec

SomeModel.stub_chain(:uninteresting, :where) {mock_some_model} 
0

Provare a passare su Arel, come potrebbe essere il caso che gli ambiti manchino.

it "should use the public, without_user, completed, and limit scopes" do 
    @chain = Entry 
    @chain.should_receive(:public).and_return(@chain.public) 
    @chain.should_receive(:without_user).with(@user).and_return(@chain.without_user(@user)) 
    @chain.should_receive(:completed).and_return(@chain.completed) 
    @chain.should_receive(:limit).with(15).and_return(Factory(:entry)) 

    Entry.public_stream(@user) 
end 
1

Prima di tutto, probabilmente non dovrebbe essere in prova incorporato nella funzionalità di Rails.

You should only be writing unit tests for code that you have written yourself (which should be second-nature if you practice TDD) – Rails ships with its own comprehensive suite of unit tests for its built-functionality – there is no point in replicating this.

Per quanto riguarda l'errore di essere gettato, penso che il problema è su questa linea:

@chain.should_receive(:limit).with(15).and_return(Factory(:entry)) 

vi aspettate la catena per restituire un Factory, che sarebbe effettivamente essere un'istanza di ActiveRecord , ma in realtà every relation returns yet another ActiveRecord::Relation.

Pertanto, l'aspettativa in sé non è corretta e potrebbe effettivamente causare l'errore che viene generato.

Ricordare che gli ambiti non restituiscono effettivamente i record previsti, finché non si esplicita esplicitamente su di essi. Inoltre, i record della relazione saranno mai restituiscono un singolo record. Saranno sempre restituire un array vuoto o un array con record.