2012-11-28 9 views
7

Diciamo che ho classi Auto e Meccanico. L'auto ha un metodo "run". Il meccanico richiede l'auto per qualche ragione. Quindi scrivo le specifiche RSpec. In meccanico mi definisco un falso clas come questo:Best practice o soluzione alternativa per le specifiche RSpec che simulano le costanti di classe

class Car; end 

e poi stub il metodo che utilizza meccanico su di esso. Tutto funziona bene se eseguo i test separatamente. Ma quando eseguo entrambi i test insieme (rspec spec/directory /) le mie specifiche Mechanic usano la vera classe Car.

Così. Credo che questo sia dovuto al fatto che le classi ruby ​​sono "aperte" e ho già caricato la classe una volta per le specifiche Car. Ma c'è un modo migliore per farlo? Quali sono le migliori pratiche per questo tipo di situazioni? Questo significa che il mio codice ha bisogno di alcuni miglioramenti perché probabilmente è strettamente accoppiato?

ho fatto un demo veloce in github: https://github.com/depy/RspecTest

risposta

2

Questo falso classe non funzionerà in quanto le classi di Ruby sono aperti.

Un approccio che è possibile utilizzare è utilizzare let per inizializzare gli oggetti nel modo desiderato e, se necessario, lavorare con la relazione su un blocco precedente. Anche i mozzi sono benvenuti all'interno dei blocchi precedenti. = p

Spero che questo ti aiuti!

+0

Ma a volte quando ho bisogno di una classe, quella classe include qualcos'altro. Devo fingere che "altro" prima di richiedere. Che ne pensi? –

+0

Questo è il comportamento che ti ho detto di fare nel blocco precedente. Come tu puoi avere 2 lascia, 1 per ciascuna delle tue classi, e sul blocco precedente, puoi fare uno stub per restituire l'altro oggetto basato su una chiamata sul primo. –

2

Penso che quello che vi serve è il test a due strati:

  • specifiche unità: test ogni classe in isolamento
  • specifiche di integrazione: il test nel suo complesso

Dato il codice come segue :

class Car 
end 

class Mechanic 
    def fix(car) 
    # do something here 
    end 
end 

Per le specifiche dell'unità, eseguire il moub delle dipendenze, ad esempio:

describe Mechanic do 
    let(:mechanic) { described_class.new } 
    let(:car)  { stub(stubbed_method_on_car: 14) } # Or just OpenStruct.new(stubbed_method_on_car: 14) 

    it 'does some stuff' do 
    mechanic.fix(car).should eq true 
    end 
end 

Per le specifiche di integrazione farei questo:

describe Mechanic do 
    let(:mechanic) { FactoryGirl.create(:mechanic) } 
    let(:car)  { FactoryGirl.create(:car) } 

    it 'does some stuff' do 
    mechanic.fix(car).should eq true 
    end 
end 
+0

Per le specifiche delle unità, puoi descrivere quali sono i metodi per i due metodi 'let'? – knownasilya

+0

Hm. L'esempio attuale è che ho NotificationService che ha un metodo di pubblicazione che viene richiamato dall'istanza Task. E all'interno di NotificationService.publish l'oggetto di notifica viene creato e pubblicato. Non voglio che l'attività sappia nulla di NotificationClass, ma sa solo che può usare NotificationService per la pubblicazione e il servizio fa tutto il resto. Ma come faccio a testare l'unità ed essere in grado di eseguire tutti i test unitari insieme non separatamente. Non desidero che NotificationService utilizzi la classe di notifica reale perché il test di notifica l'ha terminata. Spero che sia chiaro ... :) –

+0

@Knownasilya: in breve 'let' imposta un accessor alla variabile di istanza': mechanic' -> '@ mechanic' che viene ripristinata dopo ogni esempio al suo stato originario –

Problemi correlati