2012-02-03 10 views
6

Dato il codice qui sotto:Rails/RSpec - scrittura spec per metodo delegato (allow_nil opzionale)

(1) Come si va a scrivere una specifica per testare il: allow_nil => opzione falso?

(2) Vale anche la pena di scrivere una specifica da testare?

class Event < ActiveRecord::Base 
    belongs_to :league 

    delegate :name, :to => :league, :prefix => true, :allow_nil => false 
end 

describe Event do 

    context 'when delegating methods to league object' do 
    it { should respond_to(:league_name) } 
    end 

end 

Sarebbe davvero bello se si potesse estendere shoulda fare:

it { should delegate(:name).to(:league).with_options(:prefix => true, :allow_nil => false) } 
+1

Si potrebbe voler esaminare questo - qualcun altro ha fatto il lavoro per voi. https://gist.github.com/txus/807456 – weltschmerz

risposta

9

Secondo la documentazione per il modulo delegate rotaie:

Se l'oggetto delegato è pari a zero un viene sollevata un'eccezione e ciò accade indipendentemente dal fatto che nil risponda al metodo delegato. È possibile ottenere un nulla invece con l'opzione: allow_nil.

vorrei creare un oggetto Event event con un nullo , o impostare event.league = nil, quindi provare a chiamare event.name, e controllare che esso solleva un'eccezione, dato che questo è quello che dovrebbe accadere quando allow_nil è falso (che è anche l'impostazione predefinita). So RSpec ha questo idioma per il test eccezione:

lambda{dangerous_operation}.should raise_exception(optional_exception_class) 

io non sono sicuro se shoulda ha questo costrutto, anche se ci are some articles, kinda old, about how to get this behavior in shoulda.

Penso che valga la pena di testare se si tratta di un comportamento che gli utenti di questa classe possono aspettarsi o supporre accadrà, il che penso sia probabilmente vero in questo caso. Non vorrei estendere shoulda per testare "dovrebbe delegare", perché sembra più dipendente dall'implementazione: stai dicendo che il tuo evento dovrebbe sollevare un'eccezione se provi a chiamare #name quando ha una lega nil. Non è davvero importante per gli utenti di Event come lo stai facendo. Andrei anche così lontano, se vuoi affermare e prendere nota di questo comportamento, per verificare che abbia la stessa semantica di League#name, senza menzionando qualcosa su delegate, poiché questo è un approccio incentrato sul comportamento.

costruire il tuo test in base a come il codice di comportamento, non su come è costruito - testando in questo modo è una migliore documentazione per coloro che inciampano nelle vostre prove, in quanto sono più interessati alla domanda "perché è il mio evento gettando? " o "cosa può causare l'evento da lanciare?" di "è questo evento che delega?".

È possibile evidenziare questo tipo di situazione immaginando quali guasti potrebbero verificarsi se si modifica il codice in un modo che gli utenti di Event non dovrebbero preoccuparsi. Se a loro non importa, il test non dovrebbe rompersi quando lo cambi. Che cosa succede se si desidera, ad esempio, gestire autonomamente la delega, scrivendo una funzione #name che prima registra o incrementa un contatore e quindi delegati a ? testando il comportamento di eccezione, sei protetto da questa modifica, ma testando se Event è un delegato, interromperesti quel test quando apporti questa modifica - e quindi il tuo test non stava guardando ciò che è veramente circa la chiamata a #name.

In ogni caso, è tutto un semplice discorso di soapbox. tl; dr: testalo se è un comportamento su cui qualcuno potrebbe fare affidamento.Tutto ciò che non è testato è il gatto di Shroedinger: rotto e non rotto allo stesso tempo. Sinceramente, per la maggior parte del tempo questo può essere OK: è una questione di gusti se si vuole dire qualcosa di rigoroso e definitivo su come il sistema dovrebbe comportarsi, o semplicemente lasciare che sia un "comportamento non specificato".

+0

Dovrai testare l'eccezione è un RuntimeError altrimenti, semplicemente non delegando si alza un metodo non trovato. – fivetwentysix

2

Così un paio di cose qui sulla necessità o meno di provare questo:

1) Non credo che ci sia qualcosa di sbagliato in spec'ing questo comportamento. Se hai utenti che hanno bisogno di imparare il tuo software/libreria, è spesso molto utile per assicurarti che tutti i tuoi metodi che fanno parte del tuo contratto pubblico siano specificati. Se non si desidera rendere questa parte della API di questo modello, si consiglia di eseguire manualmente la delega in modo da non esporre più metodi al mondo esterno di quanto sia necessario.

2) Specifiche di questo tipo aiutano a garantire che il contratto con l'oggetto a cui si sta delegando rimanga applicato. Ciò è particolarmente utile se stai usando stub e mock nei tuoi test, dato che spesso implementano lo stesso contratto, quindi almeno sei consapevole quando questo contratto cambia.

In termini di test della parte allow_nil, sono d'accordo con Matt, l'idea migliore è assicurarsi che il campionato sia zero, quindi provare a chiamare il nome in campionato. Questo è possibile testare per garantire che venga restituito nil.

Spero che questo aiuti.