2015-08-10 19 views
13

Ho sviluppato in RoR da più di un anno, ma sto solo iniziando a utilizzare i test, usando RSpec.Come strutturare le mie cartelle di test, file e database RSpec?

Per i test modello/controller standard, di solito non ho alcun problema, ma il problema è che voglio testare alcuni complicati processi funzionali e non so come strutturare le mie cartelle/file/database di test .

Ecco una struttura di base per la mia domanda:

class Customer 
    has_one :wallet 
    has_many :orders  
    has_many :invoices, through: :orders 
    has_many :invoice_summaries 
end 

class Wallet 
    belongs_to :customer 
end 

class Order 
    has_one :invoice 
    belongs_to :customer 
end 

class Invoice 
    belongs_to :order 
    belongs_to :invoice_summary 
end 

class InvoiceSummary 
    belongs_to :customer 
    has_many :invoices 
end 

Il problema principale è che voglio simulare il ciclo di vita del mio oggetto, il che significa:

  • Instantiating clienti e portafogli che sarà essere utilizzato per tutti i test (senza reinizializzazione)

  • Simulazione del flusso di tempo, creazione e aggiornamento di più ordini/oggetti fattura e alcuni i nvoice_summaries.

Per la creazione e l'aggiornamento degli ordini/fatture/invoice_summaries, mi piacerebbe avere metodi come

def create_order_1 
    # code specific to create my first order, return the created order 
end 

def create_order_2 
    # code specific to create my second order, return the created order 
end 
. 
. 
. 
def create_order_n 
    # code specific to create my n-th order, return the created order 
end 

def bill_order(order_to_bill) 
    # generic code to do the billing of the order passed as parameter 
end 

def cancel_order(order_to_cancel) 
    # generic code to cancel the order passed as parameter 
end 

ho già trovato la gemma Timecop per simulare il flusso del tempo. Quindi, mi piacerebbe avere un test finale facile da capire che assomiglia a

# Code for the initialization of customers and wallets object 

describe "Wallet should be equal to 0 after first day" do 
    Timecop.freeze(Time.new(2015,7,1)) 
    first_request = create_request_1 
    first_request.customer.wallet.value.should? == 0 
end 

describe "Wallet should be equal to -30 after second day" do 
    Timecop.freeze(Time.new(2015,7,2)) 
    bill_order(first_request) 
    second_order = create_order_2 
    first_request.customer.wallet.value.should? == -30 
end 

describe "Wallet should be equal to -20 after third day" do 
    Timecop.freeze(Time.new(2015,7,3)) 
    bill_order(second_request) 
    cancel_order(first_request) 
    first_request.customer.wallet.value.should? == -20 
end 

describe "Three first day invoice_summary should have 3 invoices" do 
    Timecop.freeze(Time.new(2015,7,4)) 
    invoice_summary = InvoiceSummary.create(
     begin_date: Date.new(2015,7,1), 
     end_date: Date.new(2015, 7,3) 
) # real InvoiceSummary method 
    invoice_summary.invoices.count.should? == 3 
end 

Qualcuno ha già tali test? Ci sono buone pratiche per strutturare le fabbriche di oggetti, scrivere test e così via?

Ad esempio, mi è stato detto che una buona idea sarebbe quella di mettere la creazione Cliente/Portafoglio in un file db/seed.rb, ma in realtà non so cosa farmene dopo.

+0

@HunterStevens Credo che la tua modifica sia errata, perché hai rimosso qualche logica sugli ordini. 'def create_order_n; end' È diverso da 'def create_order_1; end' 'def create_order_2; end' dal momento che @vincent voleva esprimere la necessità di fare 2 cose completamente diverse. Dovresti fare attenzione prima di modificare in questo modo ... – Erowlin

+0

@Erowlin, per favore, ripristina la mia modifica. Stavo cercando di ripulire un post molto lungo. Scusate. – onebree

+0

NP, fai solo attenzione la prossima volta;). A proposito, grazie per la tua modifica, è partita da una buona intenzione! – Erowlin

risposta

5

Completamente rispondendo alla tua domanda potrebbe riempire e ha riempito libri, quindi posso solo delineare una risposta qui.

Per quanto riguarda la creazione di oggetti per testare,

  • db/seeds.rb non è per i dati di test, ma per i dati statici, non è cambiato dagli utenti, che è richiesto per l'esecuzione dell'applicazione, sia in fase di sviluppo o test o produzione. Esempi comuni di questo tipo di dati includono codici paese e ruoli utente.

  • Esistono due approcci generali per la creazione di dati di test, impianti e fabbriche.

    • Gli apparecchi sono il metodo Rails pronto all'uso. Vengono creati una volta quando viene creato il database di test. Sono veloci quando hai molti test, perché vengono creati solo una volta all'inizio della suite di test. Tuttavia, eseguono il warp test perché incoraggiano a scrivere test sui proiettori esistenti, quindi raccomando fortemente contro di loro.
    • Le fabbriche sono utilità di creazione di oggetti. Crei gli oggetti necessari in ciascun test e li elimini o li arrotoli alla fine. La maggior parte dei progetti di Rails che utilizzano fabbriche utilizzano FactoryGirl. Questo è quello che raccomando.

    Entrambi gli approcci inseriscono il codice di creazione dell'oggetto nei propri file in una directory diversa rispetto alle specifiche, impedendo di annullare i file spec. Se cerchi SO per "infissi o fabbriche" troverai molte più discussioni su entrambi.

vostre specifiche saranno più facili da capire se si mettono tutti i valori importanti, che in questo caso includono le date e gli importi, nelle specifiche in cui possono essere visti e confrontati con i risultati che si sta affermando . (In caso contrario, è necessario memorizzare le date e gli importi negli oggetti di prova per comprendere le specifiche.) È possibile fornire i metodi di creazione dell'oggetto nei parametri di prova date e amount. Potresti aver bisogno di meno metodi allora. Se hai utilizzato FactoryGirl, potrebbe essere solo una questione di specificare gli attributi created_at e amount di ciascun oggetto. Nota anche che Rails ha metodi come 1.day.from_now; se crei oggetti con date specificate in questo modo potresti non aver bisogno di timecop.

Per quanto riguarda come disporre le specifiche RSpec nel filesystem, al livello superiore, basta fare il layout identico a quello del vostro Rails app:

app/ 
    controllers/ 
    bars_controller.rb 
    foos_controller.rb 
    models/ 
    bar.rb 
    foo.rb 
    ... 
    ... 

spec/ 
    controllers/ 
    bars_controller_spec.rb 
    foos_controller_spec.rb 
    ... 
    models/ 
    bar_spec.rb 
    foo_spec.rb 
    ... 
    ... 

Se le specifiche per una singola classe diventano troppo grandi, è un segnale che la classe è troppo grande. Trova qualche schema per romperlo e testare i pezzi individualmente. Se davvero non puoi rompere la classe (una situazione rara), trasforma il file spec della classe in una directory di file spec, come ho descritto in How to break down super long specs in RSpec?.

+0

Ulteriori dettagli su [struttura di directory suggerita da RSpec qui] (https://relishapp.com/rspec/rspec-rails/docs/directory-structure). –

0

È necessario utilizzare FactoryGirl per l'attività. Configurarlo come descritto nella documentazione, e poi basta usare in questo modo:

# factories.rb 
factory :order do 
end 

# your spec 
first_order = create(:order, ...) # configure parameters of order in-place 

O fabbriche specifiche di gestire diversi tipi di richieste:

# factories.rb 
factory :expensive_order, class: Order do 
    amount 999 # have 'amount' field of Order be equal to 999 
end 

# your spec 
first_order = create(:expensive_order) 

Si può avere factorygirl gestire automaticamente le associazioni:

factory :order do 
    association :user # automatically create User association 
end 

Si sta descrivendo il problema esatto che gli sviluppatori di FactoryGirl mirano a risolvere.