ruby April 23, 2006 6:06 pm (Save post)
avendo finalmente un filo di tempo libero, vorrei parlare di un interessante problemino di approccio agli Unit Test.
Ma al momento questo margine è troppo piccolo, quindi per ora mi limito a lasciarvi ponderare questo spezzone di codice:
def special(mod, meth,*args, &block)
prev = mod.instance_method(meth)
mod.send :define_method, meth do |*a|
if args == a
block.call(*a)
else
prev.bind(mod).call(*a)
end
end
end
i test sono in fondo al post.
In pratica è un modo particolarmente stupido ed inefficiente di definire degli special case nel comportamento di un metodo.
I metodi così definiti sono in qualche modo simili a dei multimetodi mooolto depotenziati e che non interagiscono con l’ereditarietà, il che fa si che si possano facilmente incrementare le prestazioni mettendo le varie versioni speciali in un Hash.
In questo modo, invece di avere l’overhead di chiamate a funzione ricorsive si avrebbe solo il costo dell’accesso per recuperare la versione corretta.
Ovviamente c’è poi il fattore di dove mettere questo hash.. insomma in realtà si tratta di un problemino interessante che vi consiglio di affrontare, magari come kata per esercitarvi con ruby.
Sul wiki di ruby italia potete vedere le soluzioni ad un problema analogo, quello di scrivere una funzione memoize che trasformi un metodo qualunque in uno memoizzato, ovvero uno che calcoli il risultato per un certo set di argomenti una sola volta, anche a fronte di numerose chiamate.
Per sapere cosa c’entri tutto questo con i test dovete aspettare che abbia di nuovo un attimo di tempo, intanto pensateci su, i test contengono degli hint
if __FILE__ == $0
require 'test/unit'
class TC_Special < Test::Unit::TestCase
def test_one_mod
special(Kernel,
pen, \"speciale\") {\"atteso\"}
assert_equal \"atteso\", open(\"speciale\")
assert_raise(Errno::ENOENT){open \"\"}
end
def test_many_mod
for i in %w(primo secondo terzo) do
special(Kernel,
pen, i) {i}
end
for i in %w(primo terzo secondo)
assert_equal i, open(i)
end
assert_raise(Errno::ENOENT){open \"\"}
end
def test_one_class
person=Struct.new :name
special(person, :name=, \"01\") {raise}
assert_raises(RuntimeError) { person.new.name= \"01\"}
end
end
end


Finalmente trovo il tempo di leggere e cercare di capire il codice. Bello. Sarebbe inoltre molto utile per mockare chiamate di sistema, dovessi scegliere di non utilizzare DependencyInjection. Nel mondo java sei obbligato al secondo approccio, ma in ruby hai ottime alternative.
Bella anche l’idea di utilizzarlo per ‘memoizzare’, ma in questo caso il codice è incompleto, no? una volta trovato un nuovo risultato dovresti cacharlo.
non sono sicuro però del nome special…
che ne dici di una qualcosa del genere?
Kernel.override :when=>:open, :with=>”pippo” do
“sdfsdgdfgfdh”
end
avresti bisogno anche di qualcosa per smontare il mocking..
Comment by Chiaroscuro — May 2, 2006 @ 6:56 pm
si concordo, ci sarebbe bisogno di smontare il mock, però dissento sui parametri passati via keyword argument, non credo sia un caso in cui sono utili.
Certo, Module#override in effetti è più carino di #special ma lo fa sembrare troppo serio e utile ;P
Comment by gabriele — May 2, 2006 @ 11:16 pm
Kernel.mock [:open, “breakfast”] => “bacon,eggs,coffee”,
[:open, “lunch”] => “sandwich”,
[:open, “dinner”] => proc{raise “not hungry”}
che ne pensi?
Comment by Chiaroscuro — May 3, 2006 @ 9:22 am
meglio…
#
Kernel.mocking(
[:open, “breakfast”] => “bacon,eggs,coffee”,
[:open, “lunch”] => “sandwich”,
[:open, “dinner”] => proc{raise “not hungry”}
) do
our stuff here …
end
smontamento automatico a fine blocco
Comment by Chiaroscuro — May 3, 2006 @ 9:24 am
carino, ma io non avevo pensato di effettuare mock multipli insieme perché non ne ho mai sentito il bisogno, Come cavolo si dice… YAGNI
Comment by gabriele — May 3, 2006 @ 9:48 am
si, è vero, nel caso di Kernel sempre sulla chiamata open probabilmente non si applica. Metti però che vuoi mockare un pezzo di infrastruttura. Diventa utile a quel punto mockare diversi metodi.
Comment by Chiaroscuro — May 3, 2006 @ 9:58 am
That is an awfully astounding column you’ve posted.Thanks a lot for that a fantastically amazing post!
Comment by Aaron Rodgers Jersey — November 8, 2011 @ 6:53 am
Your blog has truly inspired me, especially the current article. thank you for sharing your thoughts and
the impact of them has been tremendous to me.Thank you more time and keep up with the good work.
Comment by Charles Woodson Jersey — November 8, 2011 @ 6:53 am
Thanks for sharing. A real lot of useful info here!
Comment by B.J. Raji Jersey — November 8, 2011 @ 6:54 am
These are all great comments here. Very cool article.
Comment by Clay Matthews Jersey — November 8, 2011 @ 6:54 am
very useful and interesting your article.
Comment by Donald Driver Jersey — November 8, 2011 @ 6:55 am