2012-09-28 10 views
19

Ecco un po 'di codice da M Hartl's Ruby on Rails Tutorial. Qualcuno può spiegare perché è necessaria una variabile di istanza (@user) e perché non utilizzare una variabile locale. Inoltre, poiché si suppone che le variabili di istanza siano le variabili nell'istanza di una classe, quale classe è istanziata da @user?Come funzionano le variabili di istanza in rspec?

require 'spec_helper' 

describe User do 

    before { @user = User.new(name: "Example User", email: "[email protected]") } 

    subject { @user } 

    it { should respond_to(:name) } 
    it { should respond_to(:email) } 
end 

risposta

32

Uso di una variabile locale in quel caso significherebbe che la sua portata sarebbe limitato al before e quindi provocare un errore. Il @user è di tipo Utente ma è una variabile di istanza del blocco describe. Rspec ha un po 'di magia che a run-time rende una classe fuori da ogni blocco describe. Ogni esempio (blocco it) finisce per essere una sottoclasse di detta classe. L'ereditarietà delle classi consente agli esempi di vedere @user.

cura 2017-05-14

Linked post non è più disponibile. Aggiornamento con Wayback Machine link + inlining sezione pertinente qui.

Si noti che questo è considerato un anti-pattern come descritto in questo blog post. Utilizzare invece let.

let presenta i seguenti vantaggi:

  • Si memoized quando viene utilizzato più volte in un esempio, ma non di tutti esempi.
  • È lazy-loaded, quindi non perderai tempo inizializzando la variabile per gli esempi che non la fanno riferimento.
  • Solleverà un'eccezione se si ha un errore di battitura nel nome della variabile.
+1

Oh, penso di averlo capito ora.Ho sempre pensato che il blocco descrittivo fosse usato per rendere i test più leggibili per gli umani e nient'altro. Grazie :) – TradeRaider

+0

Quel post sul blog non è più disponibile. Potrebbe valere la pena aggiornare la risposta per includere i motivi per cui l'uso di una variabile di istanza è un antipattern e rimuovere il collegamento interrotto. – keoghpe

2

subject ad it i blocchi sono in ambiti diversi, quindi le variabili locali non funzioneranno. @user appartiene alla classe generata da RSpec sotto il cofano.

12

Non è possibile utilizzare una variabile locale poiché una variabile locale esiste solo nell'ambito del metodo locale. before, subject e it generano ambiti diversi all'interno della stessa classe.

Il seguente codice

before { user = User.new(name: "Example User", email: "[email protected]") } 

alzerà una variabile non definita quando si chiama in

subject { user } 

L'istanza @user è un'istanza della classe User (dopo tutto, lo si crea con User.new).

Tuttavia, anziché le variabili di istanza si potrebbe voler utilizzare il comando let. Inoltre, se si definisce

subject { User.new(name: "Example User", email: "[email protected]") } 

l'uso di before non è necessaria. Avrai anche il vantaggio extra di ottenere un metodo subject disponibile per accedere all'istanza, uguale a definire let(:subject).

+4

+1 sull'uso di 'let':' let (: utente) {User.create (nome: "Utente di esempio", email: "[email protected]")} ' – Meltemi

+0

+1 sull'utilizzo dell'oggetto: oggetto {Utente. nuovo (nome: "Utente di esempio", email: "[email protected]")} –

Problemi correlati