2010-04-30 7 views
9

Il nocciolo del mio problema è il seguente: -Come restituire un valore dinamico da un finto Mocha in Ruby

Sto scrivendo un finto Mocha in Ruby per il metodo rappresentato come "post_to_embassy" di seguito. Non è davvero una nostra preoccupazione, allo scopo di descrivere il problema, quale sia il metodo reale. Ma ho bisogno del mock per restituire un valore dinamico. Il proc '&' di seguito è in esecuzione correttamente al posto del metodo effettivo. Ma il metodo "with" in Mocha consente solo di restituire valori booleani. Quindi il codice qui sotto è zero. Ho bisogno di emettere il valore che viene passato attraverso orderInfoXml. Qualcuno sa di un metodo alternativo che posso usare?

require 'rubygems' 
require 'mocha' 
include Mocha::API 

class EmbassyInterface 
    def post_to_embassy(xml) 
    puts "This is from the original class:-" 
    puts xml 
    return xml 
    end 
end 

orderInfoXml = "I am THE XML" 

mock = EmbassyInterface.new 
prc = Proc.new do |orderXml| 
    puts "This is from the mocked proc:-" 
    puts orderXml 
    orderXml 
end 

mock.stubs(:post_to_embassy).with(&prc) 
mock_result = mock.post_to_embassy(orderInfoXml) 
p mock_result 
#p prc.call("asd") 

uscita: -

This is from the mocked proc:- 
I am THE XML 
nil 

risposta

0

non ho trovato un modo per rendere l'uscita di un metodo deriso completamente dinamico, ma se si dispone di un numero limitato, noto numero di ingressi è possibile ottenere il uscita per funzionare correttamente.

require 'rubygems' 
require 'mocha' 
include Mocha::API 

class EmbassyInterface 
    def post_to_embassy(xml) 
    "original: #{xml}" 
    end 
end 

to_mock = EmbassyInterface.new 
orderInfoXml1 = "I am the first XML." 
orderInfoXml2 = "I am the second XML." 

p to_mock.post_to_embassy(orderInfoXml1) 

prc = Proc.new do |xml| 
    "mocked: #{xml}" 
end 
to_mock.stubs(:post_to_embassy).with(orderInfoXml1).returns(prc.call(orderInfoXml1)) 
to_mock.stubs(:post_to_embassy).with(orderInfoXml2).returns(prc.call(orderInfoXml2)) 

p to_mock.post_to_embassy(orderInfoXml1) 
p to_mock.post_to_embassy(orderInfoXml2) 
p to_mock.post_to_embassy(orderInfoXml1) 

uscita:

"original: I am the first XML." 
"mocked: I am the first XML." 
"mocked: I am the second XML." 
"mocked: I am the first XML." 
+0

penso che questo risposta è un po 'fuorviante. Sebbene sia corretto suggerire che è possibile utilizzare Expectation # con per specificare diversi valori di ritorno per diversi valori di parametro, l'uso di Procs non è necessario per specificare i valori di ritorno. –

+0

Vero, il Proc non è necessario. Potrei aver specificato i valori di ritorno come stringhe, direttamente. Ho usato un Proc nel mio codice di esempio per rispecchiare più da vicino la domanda. – metavida

4

non sono sicuro se c'è un metodo perfetto per questo. Ma per rendere la vita più facile, che per sopprimere ogni possibile risposta (come descritto in un'altra risposta), si può andare con il metodo yields di Mocha.

require "rubygems" 
require "mocha" 

include Mocha::API 

class EmbassyInterface 

    def post_to_embassy(xml) 
    puts "This is form the original class:-" 
    puts xml 
    xml 
    end 
end 

order_info_xml = "I am the xml" 

mock = EmbassyInterface.new 

prc = Proc.new do |order_xml| 
    puts "This is from the mocked proc:-" 
    puts order_xml 
    order_xml 
end 

mock.stubs(:post_to_embassy).yields prc 

prc_return = nil 

mock.post_to_embassy { |value| prc_return = value.call("hello world") } 
puts prc_return 

mock.post_to_embassy { |value| prc_return = value.call("foo") } 
puts prc_return 

uscite:

This is from the mocked proc:- 
hello world 
hello world 

This is from the mocked proc:- 
foo 
foo 

Questo richiederà di assegnare il ritorno del vostro prc, e non è esattamente abbastanza (IMO). Ma non devi eliminare ogni aspettativa, il che ti darà un bel po 'di libertà.

+3

Questo non è l'uso previsto dei rendimenti di Expectation #. Non raccomanderei questa tecnica. –

3

In generale, normalmente è meglio specificare valori di ritorno espliciti nei test. Tende a rendere i test difficili da capire e difficili da mantenere se si introduce una logica separata nel determinare quale valore restituire.

vorrei suggerire che si sia di utilizzare Expectation#with con adatto ParameterMatchers per definire in modo esplicito valori di ritorno per i diversi valori dei parametri o utilizzare la funzionalità StateMachine.

1

Mocha non sembra supportare questo. Aggiungi questo al vostro test_helper.rb:

# Replace klass's method_name with method_implementation 
def stub_replace(klass, method_name, &method_implementation) 
    klass.singleton_class.send(:alias_method, "#{method_name}_mock_backup", method_name) 
    klass.define_singleton_method(method_name, method_implementation) 
end 

def undo_stub_replace(klass, method_name) 
    klass.singleton_class.send(:alias_method, method_name, "#{method_name}_mock_backup") 
end 

quindi sostituire le ultime 4 linee del vostro test con:

stub_replace(EmbassyInterface, :post_to_embassy, &prc) 
mock_result = mock.post_to_embassy(orderInfoXml) 
p mock_result 

# cleanup 
undo_stub_replace(EmbassyInterface, :post_to_embassy)