2014-12-07 21 views
10

Sto riscontrando un errore nel trovare SO/Google in questo caso particolare. Ho un modulo con funzioni e per usarle, devi creare una classe che includa/estenda il modulo a seconda che tu voglia metodi di istanza o metodi di classe.Test dei moduli di Ruby con rspec

module A 
    def say_hello name 
    "hello #{name}" 
    end 

    def say_bye 
    "bye" 
    end 
end 

Come faccio a testare questo modulo utilizzando RSpec?

Ho qualcosa di simile, e non sono sicuro di dove sia il punto in cui dovrei creare la classe ed estendere il modulo.

describe A do 
    class MyClass 
    extend A 
    end 

    before(:each) { @name = "Radu" } 

    describe "#say_hello" do 
    it "should greet a name" do 
     expect(Myclass.say_hello(@name)).to eq "hello Radu" 
    end 
    end 
end 

Grazie!

+1

tuo metodo non restituisce questo valore. Dovresti controllare che lo metta, in modo che il metodo 'puts' chiamato una volta con argomento' ciao Radu' – zishe

+0

@zishe yep 'say_hello (@name)' return 'nil'. –

+1

Questo è stato un esempio stupido. Ho metodi che restituiscono le cose. La mia preoccupazione è come usare estendere in rspec – radubogdan

risposta

24

È possibile creare una classe anonima nei test:

describe A do 
    let(:extended_class) { Class.new { extend A } } 
    let(:including_class) { Class.new { include A } } 

    it "works" do 
    # do stuff with extended_class.say_hello 
    # do stuff with including_class.new.say_hello 
    end 
end 

di vedere qualcosa di simile nel codice vero e proprio, ho usato questa strategia per testing my attr_extras lib.

Detto questo, include e extend sono funzionalità standard di Ruby, quindi non testerei che ogni modulo funzioni sia quando è incluso sia quando si estende - di solito è un dato.

Se si crea una classe con nome nel test, come si fa nella domanda, credo che la classe esisterà globalmente per tutta la durata dell'esecuzione del test. Quindi questa classe trapelerà tra ogni test della tua suite di test, causando potenzialmente conflitti da qualche parte.

Se si utilizza let per creare una classe anonima, sarà disponibile solo all'interno di questo particolare test. Non c'è una costante globale che punta ad esso che potrebbe essere in conflitto con altri test.

+0

Ho ancora il metodo 'non definito' my_method 'per # ', ma forse è colpa mia . Grazie per la pronta risposta. – radubogdan

+0

@radubogdan Ho provato a incollare [questo codice esatto (collegamento Gist)] (https://gist.github.com/henrik/8d400883a99779de4926) a un test RSpec esistente e passa, quindi forse qualcos'altro è sbagliato? –

+0

Sì, sicuramente qualcos'altro è sbagliato, ma non riesco a trovare cosa. Potrebbe essere spec_helper? (Ho creato spec_helper usando rspec --init, la versione di rspec è 3.1.7) – radubogdan

0

per dare una mano futuri lettori, ecco un esempio ho cominciato ad andare usando la soluzione @ s' Henrik-n:

# slim_helpers.rb 
module SlimHelpers 

    # resourceToTitle converts strings like 'AWS::AutoScaling::AutoScalingGroup' 
    # to 'Auto Scaling Group' 
    def resourceToTitle(input) 
    input.split('::')[-1].gsub(/([A-Z])/, ' \1').lstrip 
    end 

end 

# slim_helpers_spec.rb 
require_relative '../slim_helpers' 

describe SlimHelpers do 

    # extended class 
    let(:ec) { Class.new { extend SlimHelpers } } 

    it "converts AWS resource strings to titles" do 
    out = ec.resourceToTitle('AWS::AutoScaling::AutoScalingGroup') 
    expect(out).to eq 'Auto Scaling Group' 
    end 
end 
+0

Si potrebbe anche usare 'Class.extend (SlimHelpers)' se è necessario testare i metodi della classe. – czerasz