2011-02-03 13 views
6

Sono nuovo a Rspec e sto provando a impostare un test per un profilo utente. Il profilo appartiene all'utente.Rspec Mocking: ActiveRecord :: AssociationTypeMismatch

Ora, ho un'integrazione API con un sito di terze parti che funziona tramite il Modello utente, ma alcune informazioni per quel collegamento API sono contenute in Profile, quindi ho un filtro "after_update" su Profile che dice al utente genitore da salvare, che attiva un aggiornamento dell'API.

Sto provando a scrivere un test per questo, e sto ricevendo un ActiveRecord :: AssociationTypeMismatch. Il motivo è che sto usando un utente fittizio, ma sto provando a testare che quando Profile è aggiornato, invia: save to User. Inoltre, il modello User ha un processo di conferma e-mail e le chiamate API in questione nel suo processo di creazione, quindi non è davvero l'ideale per creare un utente solo per testarlo.

Ecco la mia prova:

it "should save the parent user object after it is saved" do 
    user = double('user', :save => true) 
    profile = Profile.create(:first_name => 'John', :last_name => 'Doe') 
    profile.user = user 

    user.should_receive(:save) 
end 

Quindi, chiaramente l'errore di ActiveRecord è causato da cercando di associare un utente finto con un profilo che si aspetta un vero e proprio utente da associare.

La mia domanda è: come si evita questo tipo di problema durante la scrittura di test su rotaia? Tutto quello che voglio fare questo test è assicurarsi che Profile chiama: salva sul suo utente genitore. C'è un modo più intelligente per fare questo o una soluzione alternativa per l'errore ActiveRecord?

Grazie!

+0

Personalmente userei qualcosa come factory_girl per creare un oggetto utente già confermato e quindi impostare l'attesa 'save' su quello. Non sei in grado di simulare un utente confermato senza passare attraverso la procedura di posta elettronica? Questo fa scattare alcuni allarmi riguardo al design del codice. –

+0

Bene, il tuo suggerimento è finito per essere il modo in cui dovevo andare. Sono stato in grado di isolare l'API che non volevo chiamare dicendo al controller di non attivare quella chiamata nell'ambiente di test, in modo che mi permettesse di lavorare con gli oggetti Factory come previsto. Tuttavia, ho dovuto riattivare le azioni API per testare le integrazioni, quindi alla fine ho abbandonato questo approccio e sto consentendo all'ambiente sandbox dell'API di riempire i dati spazzatura che devo eliminare periodicamente. Non è quello che avrei preferito, ma mi fa provare. – Andrew

risposta

3

Ho trovato l'unico modo sono stato in grado di aggirare questo problema è stato quello di utilizzare un utente di fabbrica, invece di un mock. È frustrante, ma quando si testano i callback tra due modelli di ActiveRecord è necessario utilizzare i modelli reali, altrimenti le chiamate di salvataggio falliranno, il ciclo di vita non si verificherà e le callback non potranno essere testate.

+0

Non si dovrebbero verificare le callback nelle specifiche del modello pertinente? – Starkers

11

Si dovrebbe essere in grado di utilizzare un mock_model per questo:

it "should save the parent user object after it is saved" do 
    user = mock_model(User) 
    user.should_receive(:save).and_return(true) 
    profile = Profile.create(:first_name => 'John', :last_name => 'Doe') 
    profile.user = user 
end 
+0

Ho provato questo, e non ha funzionato. – Andrew

+2

Cosa nello specifico? – zetetic

+0

Funziona. Grazie! –