ruby, oop April 26, 2006 6:19 am (Save post)
Questo post si basa sul piccolo lavoro fatto la volta scorsa per creare special case nei metodi .
Avendo a disposizione quello strumento posso affrontare una delle Grandi Domande: mi conviene fare refactoring per rendere il codice più facilmente testabile se posso evitarlo?
Nel dettaglio: ho uno script che prende in automatico dei dati da risorse su web, e poi fa un grafico con i cambiamenti, insomma una scopiazzatura di EhList, fatta per giocare con le api di Yahoo! SiteExplorer in ruby
Poiché i servizi sono tutti differenti esiste un metodo specifico per accedere ad ognuno di essi, catturato nell’esistenza di una classe Provider e di varie sottoclassi, ognuna con una descrizione, un metodo specifico per recuperare le informazioni remote ed eventuali altre cose.
Un esempio di provider è:
class YahooProvider < Provider
DESC=\"Yahoo SE inbound links\"
APPID=\"myAppId\"
URL=\"url yahoo SE?query=%s&appid=%s\"
def initialize(name)
text=open(URL%[name,APPID]).read
@result=Mapping.xml2obj(text)
end
def results_size
@result.xmlattr_totalResultsAvailable
end
end
se state imprecando contro di me perché non chiudo la connessione aperta con open() potete calmarvi, lo script completa le operazioni in meno di un minuto e si chiude, il che fa si che le risorse vengano comunque recuperate.
Ora: come testare questo provider? In particolare, come testare l’operazione di parsing dell’xml?
La cosa più ovvia è passargli dei dati preconfezionati, magari presi da un’esecuzione precedente dello script, e verificare che li interpreti correttamente.
Solo che è il metodo initialize ad eseguire sia la letttura dei dati che il parsing.
La soluzione che permette di testare meglio tutto ciò è di spostare queste funzionalità in un altro posto per poterle testare in isolamento, con una cosa come questa:
def read_data()
open(URL%[name,APPID]).read
end
def parse(xml)
Mapping.xml2obj(xml)
end
def initialize(name)
testo=read_data()
@result= parse(testo)
end
Se è vero che questo approccio introduce una certa flessibilità è anche vero che si tratta di una flessibilità non necessaria, o meglio di una fattorizzazione del codice in più parti che però non è utile in quanto non userò mai una delle funzionalità separatamente dall’altra.
Insomma, sto facendo una cosa di cui non ho bisogno solo per far felici i test, che non è una cosa terribile, ma la eviterei.
Ma, se siete arrivati a leggere fin qui probabilmente sapete già cosa possiamo fare in questo caso:
require 'stringio' special Kernel, \"open\" do StringIO.new(\"xml di prova\") end assert_equal valore_atteso, YahooProvider.new(url).results_size
è un hack, e non è molto nella filosofia di come dovrebbero essere i test probabilmente..
ma funziona e non aggiunge complicazioni al codice originale.
La domanda è: cosa è giusto fare? E’ giusto perseguire un approccio alla scrittura di test che è tipico in altri ambienti anche se in questo caso ne posso fare a meno sfruttando le potenzialità di ruby?
Infine, se vi state chiedendo che cosa significhi la frase relativa ad open() nel titolo, sappiate che stavo pensando che sarebbe molto carino poter usare qualcosa come
open(”mock://foo”), ed in realtà è possibile farlo con open-uri.rb, magari in futuro ne parlerò. Però non è builtin, uffa


occhio ai symbols nel codice. i due punti seguiti da lettere diventano faccine!
:O
Comment by Chiaroscuro — April 26, 2006 @ 7:39 am
lol! e mo chissà come lo tolgo
Comment by gabriele — April 26, 2006 @ 10:30 am
uhm.. domanda difficile.
la saggezza tradizionale dice che obbligare a fare dependency injection rende il codice più sano.. ma forse è solo un artefatto di un mondo poco dinamico.
è una domanda filosofica ad ampio raggio a cui non ho risposta. nello stesso campo a mio avviso cadono domande del tipo “ma abbiamo bisogno dell’ereditarietà in ruby?”, “se tutto è convenzione perchè avere public e private?”, etc.
mi accorgo spesso di essere pieno di preconcetti del mondo statico di java ed è difficile staccarsene.
perchè non proponi alcuni semplici kata in lista o su blog che potrebbero mettere a nudo forze e debolezze dei due approcci? sarebbe divertente esplorare in modo sistematico.
Comment by Chiaroscuro — May 2, 2006 @ 7:02 pm