In RSpec, in particolare la versione> = 3, v'è alcuna differenza tra:RSpec consentire/aspettarsi vs solo aspettare/and_return
- Utilizzando
allow
per impostare le aspettative dei messaggi con parametri che restituiscono test raddoppia, e quindi utilizzandoexpect
per fare un'affermazione sul test restituita raddoppia - usando solo
expect
per impostare l'aspettativa con i parametri e restituire il test doppia
o è tutto solo la semantica? So che fornire/specificare un valore di ritorno con expect
era the syntax in RSpec mocks 2.13, ma per quanto posso vedere, the syntax changed in RSpec mocks 3 per utilizzare allow
.
Tuttavia, nel codice (passaggio) riportato di seguito, utilizzando allow
/expect
o semplicemente expect
/and_return
sembra generare lo stesso risultato. Se uno sintassi è stata favorita rispetto ad un altro, forse, mi sarei aspettato che ci sia un qualche tipo di preavviso disapprovazione, ma dal momento che non v'è, sembrerebbe che entrambe le sintassi sono considerati validi:
class Foo
def self.bar(baz)
# not important what happens to baz parameter
# only important that it is passed in
new
end
def qux
# perform some action
end
end
class SomethingThatCallsFoo
def some_long_process(baz)
# do some processing
Foo.bar(baz).qux
# do other processing
end
end
describe SomethingThatCallsFoo do
let(:foo_caller) { SomethingThatCallsFoo.new }
describe '#some_long_process' do
let(:foobar_result) { double('foobar_result') }
let(:baz) { double('baz') }
context 'using allow/expect' do
before do
allow(Foo).to receive(:bar).with(baz).and_return(foobar_result)
end
it 'calls qux method on result of Foo.bar(baz)' do
expect(foobar_result).to receive(:qux)
foo_caller.some_long_process(baz)
end
end
context 'using expect/and_return' do
it 'calls qux method on result of Foo.bar(baz)' do
expect(Foo).to receive(:bar).with(baz).and_return(foobar_result)
expect(foobar_result).to receive(:qux)
foo_caller.some_long_process(baz)
end
end
end
end
Se ho deliberatamente fare i test falliscono cambiando il passato-in baz
parametro nella aspettativa di un diverso doppia prova, gli errori sono praticamente la stessa:
1) SomethingThatCallsFoo#some_long_process using allow/expect calls quux method on result of Foo.bar(baz)
Failure/Error: Foo.bar(baz).qux
<Foo (class)> received :bar with unexpected arguments
expected: (#<RSpec::Mocks::Double:0x3fe97a0127fc @name="baz">)
got: (#<RSpec::Mocks::Double:0x3fe97998540c @name=nil>)
Please stub a default value first if message might be received with other args as well.
# ./foo_test.rb:16:in `some_long_process'
# ./foo_test.rb:35:in `block (4 levels) in <top (required)>'
2) SomethingThatCallsFoo#some_long_process using expect/and_return calls quux method on result of Foo.bar(baz)
Failure/Error: Foo.bar(baz).qux
<Foo (class)> received :bar with unexpected arguments
expected: (#<RSpec::Mocks::Double:0x3fe979935fd8 @name="baz">)
got: (#<RSpec::Mocks::Double:0x3fe979cc5c0c @name=nil>)
# ./foo_test.rb:16:in `some_long_process'
# ./foo_test.rb:43:in `block (4 levels) in <top (required)>'
Quindi, ci sono differenze reali tra questi due test, sia nel risultato o intento espresso, o è solo semantica e/o preferenza personale? Dovrebbe essere utilizzato allow
/expect
su expect
/and_return
in generale in quanto sembra che sia la sintassi di sostituzione, o ognuno di essi è destinato ad essere utilizzato in scenari di test specifici?
Aggiornamento
Dopo aver letto Mori's answer 's, ho commentato la linea Foo.bar(baz).qux
dal codice esempio di cui sopra, ed ha ottenuto i seguenti errori:
1) SomethingThatCallsFoo#some_long_process using allow/expect calls qux method on result of Foo.bar(baz)
Failure/Error: expect(foobar_result).to receive(:qux)
(Double "foobar_result").qux(any args)
expected: 1 time with any arguments
received: 0 times with any arguments
# ./foo_test.rb:34:in `block (4 levels) in <top (required)>'
2) SomethingThatCallsFoo#some_long_process using expect/and_return calls qux method on result of Foo.bar(baz)
Failure/Error: expect(Foo).to receive(:bar).with(baz).and_return(foobar_result)
(<Foo (class)>).bar(#<RSpec::Mocks::Double:0x3fc211944fa4 @name="baz">)
expected: 1 time with arguments: (#<RSpec::Mocks::Double:0x3fc211944fa4 @name="baz">)
received: 0 times
# ./foo_test.rb:41:in `block (4 levels) in <top (required)>'
- Il
allow
spec non riesce perché lafoobar_result
double non riesce a stare in piedi per il risultato diFoo.bar(baz)
, e quindi non ha mai chiamato#qux
- Il
expect
spec non riesce al punto diFoo
mai ricevere.bar(baz)
quindi non abbiamo nemmeno arriviamo al punto di interrogare ilfoobar_result
doppia
un senso: non è solo un cambiamento di sintassi, e che expect
/and_return
ha uno scopo diverso da allow
/expect
.Ho davvero dovuto controllare il luogo più ovvio: il RSpec Mocks README, in particolare, le seguenti sezioni: