Tips http://blogs.ugidotnet.org/antonioganci/category/Tips.aspx Tips it-IT Antonio Ganci Subtext Version 2.6.0.0 Accedere ad un database sqlite con Ruby http://blogs.ugidotnet.org/antonioganci/archive/2012/01/02/accedere-ad-un-database-sqlite-con-ruby.aspx <p> In questo post vedremo come accedere ad un database <a href="http://www.sqlite.org/">sqlite</a> utilizzando Ruby. La scelta di sqlite è dovuta alla sua estrema semplicità di gestione, in quanto il database consiste in un unico file. </p> <p> Per prima cosa occorre installare una libreria per poterlo utilizzare da ruby. Basta digitare da terminale <code>gem install sqlite3-ruby</code>. </p> <p> Ora creiamo il file sqlite-test.rb con il seguente contenuto: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'sqlite3'</span> <span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'test/unit'</span> <span style="color:#e66170; font-weight:bold; ">class</span> DatabaseTest &lt; Test::Unit::TestCase <span style="color:#e66170; font-weight:bold; ">def</span> setup @db <span style="color:#d2cd86; ">=</span> SQLite3::Database<span style="color:#d2cd86; ">.</span><span style="color:#e66170; font-weight:bold; ">new</span> <span style="color:#00c4c4; ">'test.db'</span> <span style="color:#e66170; font-weight:bold; ">end</span> <span style="color:#e66170; font-weight:bold; ">def</span> teardown @db<span style="color:#d2cd86; ">.</span>close <span style="color:#e66170; font-weight:bold; ">end</span> <span style="color:#e66170; font-weight:bold; ">def</span> test_create assert File<span style="color:#d2cd86; ">.</span>exist? <span style="color:#00c4c4; ">'test.db'</span> <span style="color:#e66170; font-weight:bold; ">end</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p> Come si puo' vedere dal test il database consiste in un unico file test.db creato nella stessa directory. Se lanciamo il test abbiamo barra verde. </p> <p> Proviamo ora a creare una tabella e ad inserire alcuni dati. Aggiungiamo quindi il test: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">def</span> test_create_table sql <span style="color:#d2cd86; ">=</span> &lt;&lt;SQL create table names <span style="color:#d2cd86; ">(</span> id int primary key, name text <span style="color:#d2cd86; ">)</span>; SQL @db<span style="color:#d2cd86; ">.</span>execute sql assert_equal @db<span style="color:#d2cd86; ">.</span>execute<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">'select * from names'</span><span style="color:#d2cd86; ">)</span>, <span style="color:#d2cd86; ">[</span><span style="color:#d2cd86; ">]</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p> Proviamo a lanciarlo: Barra verde. Se proviamo però a rilanciarlo otteniamo l'errore: <code>SQLite3::SQLException: table names already exists</code>. Per risolvere il problema cancelliamo la tabella, se esiste, prima di crearla utilizzando il comando: <code>drop table if exists names;</code>. Un'altra alternativa potrebbe essere la cancellazione del file di database. </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">def</span> test_create_table sql <span style="color:#d2cd86; ">=</span> &lt;&lt;SQL drop table <span style="color:#e66170; font-weight:bold; ">if</span> exists names; create table names <span style="color:#d2cd86; ">(</span> id int primary key, name text <span style="color:#d2cd86; ">)</span>; SQL @db<span style="color:#d2cd86; ">.</span>execute_batch sql assert_equal @db<span style="color:#d2cd86; ">.</span>execute<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">'select * from names'</span><span style="color:#d2cd86; ">)</span>, <span style="color:#d2cd86; ">[</span><span style="color:#d2cd86; ">]</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p> Notare che ho modificato execute con execute_batch perché altrimenti sarebbe stata eseguita solo una delle due query. </p> <p> A questo punto siamo pronti per inserire alcuni dati e verificare che siano presenti nella tabella </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">def</span> test_create_table sql <span style="color:#d2cd86; ">=</span> &lt;&lt;SQL drop table <span style="color:#e66170; font-weight:bold; ">if</span> exists names; create table names <span style="color:#d2cd86; ">(</span> id int primary key, name text <span style="color:#d2cd86; ">)</span>; insert into names values<span style="color:#d2cd86; ">(</span><span style="color:#008c00; ">1</span>, <span style="color:#00c4c4; ">'a'</span><span style="color:#d2cd86; ">)</span>; insert into names values<span style="color:#d2cd86; ">(</span><span style="color:#008c00; ">2</span>, <span style="color:#00c4c4; ">'b'</span><span style="color:#d2cd86; ">)</span>; SQL @db<span style="color:#d2cd86; ">.</span>execute_batch sql assert_equal @db<span style="color:#d2cd86; ">.</span>execute<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">'select * from names'</span><span style="color:#d2cd86; ">)</span>, <span style="color:#d2cd86; ">[</span><span style="color:#d2cd86; ">[</span><span style="color:#008c00; ">1</span>, <span style="color:#00c4c4; ">'a'</span><span style="color:#d2cd86; ">]</span>, <span style="color:#d2cd86; ">[</span><span style="color:#008c00; ">2</span>, <span style="color:#00c4c4; ">'b'</span><span style="color:#d2cd86; ">]</span><span style="color:#d2cd86; ">]</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p>Come si puo' leggere dal test i dati vengono restituiti come un array di array.</p> <p> Altre informazioni su come usare sqlite le potete trovare <a href=" http://sqlite-ruby.rubyforge.org/sqlite3/faq.html">qui</a> </p><img src="http://blogs.ugidotnet.org/antonioganci/aggbug/100670.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/antonioganci/archive/2012/01/02/accedere-ad-un-database-sqlite-con-ruby.aspx Mon, 02 Jan 2012 19:04:40 GMT http://blogs.ugidotnet.org/antonioganci/archive/2012/01/02/accedere-ad-un-database-sqlite-con-ruby.aspx#feedback 2 http://blogs.ugidotnet.org/antonioganci/comments/commentRss/100670.aspx http://blogs.ugidotnet.org/antonioganci/services/trackbacks/100670.aspx Sviluppare un sito web in TDD usando Ruby e Sinatra http://blogs.ugidotnet.org/antonioganci/archive/2011/12/28/sviluppare-un-sito-web-in-tdd-usando-ruby-e-sinatra.aspx <p> In questo post illustrerò un modo per sviluppare un sito web che usa Sinatra usando la pratica del TDD. Per poter provare gli esempi occorre aver seguito i passi del mio precedente <a href="http://blogs.ugidotnet.org/AntonioGanci/archive/2011/12/27/primi-passi-con-sinatra.aspx">post</a>. </p> <p> Sinatra, come altri framework scritti in Ruby, aderisce allo standard <a href="http://rack.rubyforge.org/">Rack</a>. In sintesi basta realizzare un oggetto che risponde al messagio call, prende un hash come parametro e risponde con un vettore di tre elementi: lo status code, l'header http e il body. </p> <p> Un esempio di un oggetto che rispetta lo standard è: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">class</span> HelloWorld <span style="color:#e66170; font-weight:bold; ">def</span> call<span style="color:#d2cd86; ">(</span>env<span style="color:#d2cd86; ">)</span> <span style="color:#d2cd86; ">[</span><span style="color:#008c00; ">200</span>, <span style="color:#b060b0; ">{</span><span style="color:#00c4c4; ">"Content-Type"</span> <span style="color:#d2cd86; ">=</span>&gt; <span style="color:#00c4c4; ">"text/plain"</span><span style="color:#b060b0; ">}</span>, <span style="color:#d2cd86; ">[</span><span style="color:#00c4c4; ">"Hello world!"</span><span style="color:#d2cd86; ">]</span><span style="color:#d2cd86; ">]</span> <span style="color:#e66170; font-weight:bold; ">end</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p> Questo ha il vantaggio di avere degli oggetti già pronti per poter scrivere i test. Prima occorre da terminale eseguire il comando: <code>gem install rack-test</code> in modo da installare tutto ciò che ci serve. </p> <p> A questo punto siamo pronti a scrivere il nostro primo test (il file l'ho chiamato sitetest.rb): </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'./site'</span> <span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'test/unit'</span> <span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'rack/test'</span> <span style="color:#e66170; font-weight:bold; ">class</span> SiteTest &lt; Test::Unit::TestCase <span style="color:#e66170; font-weight:bold; ">def</span> test_homepage browser <span style="color:#d2cd86; ">=</span> Rack::Test::Session<span style="color:#d2cd86; ">.</span><span style="color:#e66170; font-weight:bold; ">new</span><span style="color:#d2cd86; ">(</span>Rack::MockSession<span style="color:#d2cd86; ">.</span><span style="color:#e66170; font-weight:bold; ">new</span><span style="color:#d2cd86; ">(</span>Sinatra::Application<span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span> browser<span style="color:#d2cd86; ">.</span>get <span style="color:#00c4c4; ">'/'</span> assert browser<span style="color:#d2cd86; ">.</span>last_response<span style="color:#d2cd86; ">.</span>ok? <span style="color:#e66170; font-weight:bold; ">end</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p> Creiamo anche il file (site.rb) dell'applicazione che per ora non ha impostato nessun routing: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'sinatra'</span> </pre> <p> </p> <p>Se ora lanciamo il test con il comando <code>ruby sitetest.rb</code>. Vediamo che l'assert fallisce.</p> <p>Il codice minimo per la barra verde è:</p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'sinatra'</span> get <span style="color:#00c4c4; ">'/'</span> <span style="color:#e66170; font-weight:bold; ">do</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p>Rilanciamo il test ed ecco la prima barra verde!</p> <p>A questo punto vogliamo che la nostra pagina abbia il contenuto Hello World. Aggiungiamo quindi un assert:</p> <pre style="color:#d1d1d1;background:#000000;">assert_equal browser<span style="color:#d2cd86; ">.</span>last_response<span style="color:#d2cd86; ">.</span>body, <span style="color:#00c4c4; ">'Hello World'</span> </pre> <p> </p> <p>Lanciamo nuovamente il test ed otteniamo il messaggio:</p> <pre> 1) Failure: test_homepage(SiteTest) [sitetest.rb:13]: &lt;""&gt; expected but was &lt;"Hello World"&gt;. </pre> <p>Modifichiamo il codice di produzione per la barra verde:</p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">require</span> <span style="color:#00c4c4; ">'sinatra'</span> get <span style="color:#00c4c4; ">'/'</span> <span style="color:#e66170; font-weight:bold; ">do</span> <span style="color:#00c4c4; ">'Hello World'</span> <span style="color:#e66170; font-weight:bold; ">end</span> </pre> <p> </p> <p>Alcune note:</p> <ul> <li>Affinchè un metodo venga eseguito dal test runner deve iniziare per test</li> <li><code>Sinatra::Application</code> è l'oggetto che rispetta lo standard rack</li> <li>Maggiori dettagli su come scrivere i test usando Rack e Sinatra sono <a href="http://www.sinatrarb.com/testing.html">qui</a></li> </ul> <p> Buon divertimento. </p> <img src="http://blogs.ugidotnet.org/antonioganci/aggbug/100658.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/antonioganci/archive/2011/12/28/sviluppare-un-sito-web-in-tdd-usando-ruby-e-sinatra.aspx Wed, 28 Dec 2011 18:30:11 GMT http://blogs.ugidotnet.org/antonioganci/archive/2011/12/28/sviluppare-un-sito-web-in-tdd-usando-ruby-e-sinatra.aspx#feedback 2 http://blogs.ugidotnet.org/antonioganci/comments/commentRss/100658.aspx http://blogs.ugidotnet.org/antonioganci/services/trackbacks/100658.aspx Ridurre la complessità del sistema implementando un interfaccia in modo esplicito http://blogs.ugidotnet.org/antonioganci/archive/2011/12/07/ridurre-la-complessita-del-sistema-implementando-un-interfaccia-privatamente.aspx <p> Un <a href="http://jfranzoi.wordpress.com/">collega</a> mi ha suggerito una tecnica interessante quando si è in presenza di codice legacy. </p> <p> Nella nostra codebase abbiamo creato l'astrazione ICommitCommand per modificare i dati delle risorse esterne nei setup dei un test di accettazione in cui utilizziamo i sistemi reali e non dei fake. Nel caso specifico la scrittura su un indice di Lucene e la modifica di alcuni dati nel db. </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">interface</span> ICommitCommand <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">void</span> Execute<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> </pre> <p> </p> <p> Inizialmente avevo creato l'oggetto: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">class</span> LuceneCommand <span style="color:#d2cd86; ">:</span> ICommitCommand <span style="color:#b060b0; ">{</span> LuceneClient _client<span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">public</span> LuceneCommand<span style="color:#d2cd86; ">(</span>LuceneClient client<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> _client <span style="color:#d2cd86; ">=</span> client<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#e66170; font-weight:bold; ">public</span> <span style="color:#e66170; font-weight:bold; ">void</span> Execute<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> _client<span style="color:#d2cd86; ">.</span>Update<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span> </pre> <p> </p> <p> LuceneCommand è un adapter per l'interfaccia ICommitCommand. Il problema dell'oggetto è che soffre dello smell <a href="http://www.codinghorror.com/blog/2006/05/code-smells.html">Lazy Class</a> (cioè una classe che fa troppo poco). Un modo per risolverlo è quello di fare implementare l'interfaccia direttamente a LuceneClient. </p> <p> Purtroppo il metodo Execute non ha molto significato per LuceneClient. La soluzione che abbiamo adottato è quella di farlo implementare in modo esplicito: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">class</span> LuceneClient <span style="color:#d2cd86; ">:</span> ICommitCommand <span style="color:#b060b0; ">{</span> <span style="color:#d2cd86; ">.</span><span style="color:#d2cd86; ">.</span><span style="color:#d2cd86; ">.</span> <span style="color:#e66170; font-weight:bold; ">void</span> ICommitCommand<span style="color:#d2cd86; ">.</span>Execute<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> _client<span style="color:#d2cd86; ">.</span>Update<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#d2cd86; ">.</span><span style="color:#d2cd86; ">.</span><span style="color:#d2cd86; ">.</span> <span style="color:#b060b0; ">}</span> </pre> <p> </p> <p> In questo modo se utilizzo direttamente LuceneClient non posso chiamare il metodo Execute, mentre se ne ho un riferimento come ICommitCommand posso chiamare il metodo. </p> <p> Questa tecnica viene sfruttata anche nel .net framework per l'oggetto Dictionary che implementa il metodo Add(KeyValuePair) privatamente: </p> <pre style="color:#d1d1d1;background:#000000;">var dictionary <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">new</span> Dictionary<span style="color:#d2cd86; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">int</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">string</span><span style="color:#d2cd86; ">&gt;</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> dictionary<span style="color:#d2cd86; ">.</span>Add<span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">new</span> KeyValuePair<span style="color:#d2cd86; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">int</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">string</span><span style="color:#d2cd86; ">&gt;</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#9999a9; ">// Error</span> var d <span style="color:#d2cd86; ">=</span> <span style="color:#d2cd86; ">(</span>IDictionary<span style="color:#d2cd86; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">int</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">string</span><span style="color:#d2cd86; ">&gt;</span><span style="color:#d2cd86; ">)</span> dictionary<span style="color:#b060b0; ">;</span> d<span style="color:#d2cd86; ">.</span>Add<span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">new</span> KeyValuePair<span style="color:#d2cd86; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">int</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">string</span><span style="color:#d2cd86; ">&gt;</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#9999a9; ">// ok</span> </pre> <p> </p> <p> Il vantaggio di questa soluzione è che riduce la complessità del sistema, evitando il proliferare di adapter che non fanno altro che permettere ad una classe di implementare l'interfaccia desiderata. </p> <img src="http://blogs.ugidotnet.org/antonioganci/aggbug/100608.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/antonioganci/archive/2011/12/07/ridurre-la-complessita-del-sistema-implementando-un-interfaccia-privatamente.aspx Wed, 07 Dec 2011 20:32:15 GMT http://blogs.ugidotnet.org/antonioganci/archive/2011/12/07/ridurre-la-complessita-del-sistema-implementando-un-interfaccia-privatamente.aspx#feedback 2 http://blogs.ugidotnet.org/antonioganci/comments/commentRss/100608.aspx http://blogs.ugidotnet.org/antonioganci/services/trackbacks/100608.aspx Test automatico per verificare che l'html non contenga errori http://blogs.ugidotnet.org/antonioganci/archive/2011/03/28/test-automatico-per-verificare-che-lhtml-non-contenga-errori.aspx <p> Dopo che ci è scappato un errore nell'html del sito su cui stiamo lavorando, abbiamo deciso di scrivere un test che validi l'html prodotto. </p> <p> Per raggiungere l'obiettivo utilizziamo l'utility Tidy che si puo' scaricare da <a href="http://tidy.sourceforge.net/#binaries">qui</a> </p> <p> È un piccolo eseguibile a cui si puo' passare un html e verificare che non contenga errori. </p> <p> Il codice del test è piuttosto semplice: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#d2cd86; ">[</span>Test<span style="color:#d2cd86; ">]</span> <span style="color:#e66170; font-weight:bold; ">public</span> <span style="color:#e66170; font-weight:bold; ">void</span> ValidateHtml<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> var html <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">new</span> WebClient<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">.</span>DownloadString<span style="color:#d2cd86; ">(</span>@<span style="color:#02d045; ">"</span><span style="color:#00c4c4; ">http://someurl.com</span><span style="color:#02d045; ">"</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> process <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">new</span> Process<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>FileName <span style="color:#d2cd86; ">=</span> <span style="color:#02d045; ">"</span><span style="color:#00c4c4; ">tidy.exe</span><span style="color:#02d045; ">"</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>Arguments <span style="color:#d2cd86; ">=</span> <span style="color:#02d045; ">"</span><span style="color:#00c4c4; ">-e</span><span style="color:#02d045; ">"</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>UseShellExecute <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">false</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>CreateNoWindow <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">true</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>RedirectStandardError <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">true</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StartInfo<span style="color:#d2cd86; ">.</span>RedirectStandardInput <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">true</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>Start<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StandardInput<span style="color:#d2cd86; ">.</span>Write<span style="color:#d2cd86; ">(</span>html<span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>StandardInput<span style="color:#d2cd86; ">.</span>Close<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> process<span style="color:#d2cd86; ">.</span>WaitForExit<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> Assert<span style="color:#d2cd86; ">.</span>That<span style="color:#d2cd86; ">(</span>_process<span style="color:#d2cd86; ">.</span>ExitCode<span style="color:#d2cd86; ">,</span> Is<span style="color:#d2cd86; ">.</span>EqualTo<span style="color:#d2cd86; ">(</span><span style="color:#008c00; ">0</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">,</span> _process<span style="color:#d2cd86; ">.</span>StandardError<span style="color:#d2cd86; ">.</span>ReadToEnd<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> </pre> <p>   </p> <p> Il processo viene creato redirigendo lo standard input e lo standard error, il primo usato per inviare l'html, mentre il secondo come messaggio di errore nel caso l'Assert fallisca. L'output di tidy è piuttosto esplicativo e ci permette di correggere velocemente gli errori individuati. </p> <p> l'opzione -e indica di mostrare solo gli errori, altrimenti tidy puo' anche provare a correggerli, opzione che non utilizziamo. </p> <p> La documentazione sulle opzioni supportate da tidy la trovate <a href="http://tidy.sourceforge.net/docs/tidy_man.html">qui</a>. </p><img src="http://blogs.ugidotnet.org/antonioganci/aggbug/99884.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/antonioganci/archive/2011/03/28/test-automatico-per-verificare-che-lhtml-non-contenga-errori.aspx Mon, 28 Mar 2011 15:53:18 GMT http://blogs.ugidotnet.org/antonioganci/archive/2011/03/28/test-automatico-per-verificare-che-lhtml-non-contenga-errori.aspx#feedback 1 http://blogs.ugidotnet.org/antonioganci/comments/commentRss/99884.aspx http://blogs.ugidotnet.org/antonioganci/services/trackbacks/99884.aspx Accedere ad un field pubblico da un metodo privato in Javascript http://blogs.ugidotnet.org/antonioganci/archive/2011/02/14/accedere-ad-un-field-pubblico-da-un-metodo-privato-in.aspx <p> Oggi mi sono imbattuto in un problema imprevisto e voglio condividerlo perché potrebbe tornare utile a chi non padroneggia Javascript. </p> <p>Supponiamo di avere un oggetto definito come segue:</p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> AnObject<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>value <span style="color:#d2cd86; ">=</span> <span style="color:#008c00; ">1000</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> set_value <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span>new_value<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>value <span style="color:#d2cd86; ">=</span> new_value<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>start <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> set_value<span style="color:#d2cd86; ">(</span><span style="color:#008c00; ">5</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span> </pre> <p> L'oggetto ha un field pubblico chiamato value, un metodo pubblico chiamato start ed un metodo privato chiamato set_value. Supponiamo ora che vogliamo testarlo ed il test sia il seguente: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> an_object_test<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">test</span><span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">"an object"</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> obj <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">new</span> AnObject<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> obj<span style="color:#d2cd86; ">.</span>start<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> equal<span style="color:#d2cd86; ">(</span>obj<span style="color:#d2cd86; ">.</span>value<span style="color:#d2cd86; ">,</span> <span style="color:#008c00; ">5</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> </pre> <p> Il test sarà passerà o fallirà? Se lo eseguiamo otterremo una soprendente barra rossa, con il messaggio: <i>Expected 5 but was 1000</i>, come se il metodo privato non fosse stato eseguito. Per quale motivo? </p> <p> <b>Il this nel metodo privato non si riferisce all'oggetto AnObject, piuttosto all'oggetto globale del browser window</b>. Questo problema è spiegato nel post <a href="http://www.crockford.com/javascript/private.html">Private Members in JavaScript</a> di Douglas Crockford. In particolare la soluzione proposta è: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> AnObject<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>value <span style="color:#d2cd86; ">=</span> <span style="color:#008c00; ">1000</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> that <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> set_value <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span>new_value<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> that<span style="color:#d2cd86; ">.</span>value <span style="color:#d2cd86; ">=</span> new_value<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>start <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> set_value<span style="color:#d2cd86; ">(</span><span style="color:#008c00; ">5</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span> </pre> <p> Il motivo del field that è spiegato nel post: </p> <cite> By convention, we make a private that variable. This is used to make the object available to the private methods. This is a workaround for an error in the ECMAScript Language Specification which causes this to be set incorrectly for inner functions. </cite> <p> Tenetelo presente quando lavorate in Javascript perché potrebbe riservare spiacevoli sorprese. </p> <img src="http://blogs.ugidotnet.org/antonioganci/aggbug/99721.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/antonioganci/archive/2011/02/14/accedere-ad-un-field-pubblico-da-un-metodo-privato-in.aspx Mon, 14 Feb 2011 15:48:41 GMT http://blogs.ugidotnet.org/antonioganci/archive/2011/02/14/accedere-ad-un-field-pubblico-da-un-metodo-privato-in.aspx#feedback 6 http://blogs.ugidotnet.org/antonioganci/comments/commentRss/99721.aspx http://blogs.ugidotnet.org/antonioganci/services/trackbacks/99721.aspx Scrivere test automatici per Javascript - parte 3 http://blogs.ugidotnet.org/antonioganci/archive/2011/02/11/scrivere-test-automatici-per-javascript-parte-3.aspx <p> Prima di proseguire consiglio la lettura della <a href="http://blogs.ugidotnet.org/AntonioGanci/archive/2011/02/08/scrivere-test-automatici-per-javascript.aspx">prima parte</a> e della <a href="http://blogs.ugidotnet.org/AntonioGanci/archive/2011/02/08/scrivere-test-automatici-per-javascript-parte-2.aspx">seconda parte</a>. In questo post affronteremo l'argomento dei mock object. Una prima tentazione potrebbe essere quella di cercare una libreria di mock per Javascript, ma vista la sua natura dinamica proviamo a farne a meno. </p> <p> Partiamo da un esempio per introdurre l'argomento. Supponiamo di voler testare il seguente metodo: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> show_alert<span style="color:#d2cd86; ">(</span>text<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> alert<span style="color:#d2cd86; ">(</span>text<span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> </pre> <p> Ovviamente se eseguiamo tale metodo vedremo comparire una message box. Vediamo se riusciamo a testare l'interazione. Per prima cosa occorre che quando viene chiamato alert venga eseguita una function nostra e non quella standard. Occorre anche che quando il test termina l'esecuzione, venga ripristinata la vecchia function. </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">test</span><span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">"show alert"</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> old_alert <span style="color:#d2cd86; ">=</span> alert<span style="color:#b060b0; ">;</span> alert <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> show_alert<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">'Ciao!'</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> alert <span style="color:#d2cd86; ">=</span> old_alert<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> </pre> <p> Se proviamo ad eseguire il metodo di test in QUnit vedremo che non viene più visualizzato l'alert. In quanto abbiamo sostituito alert con una function vuota. </p> <p> Questo a noi non basta perché vogliamo testare che venga chiamato alert con un certo parametro una sola volta. Aggiungiamo quindi del comportamento al nostro mock. </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">test</span><span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">"show alert"</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> old_alert <span style="color:#d2cd86; ">=</span> alert<span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> alert_call_count <span style="color:#d2cd86; ">=</span> <span style="color:#008c00; ">0</span><span style="color:#b060b0; ">;</span> alert <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> alert_call_count<span style="color:#d2cd86; ">++</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> show_alert<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">'Ciao!'</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> equals<span style="color:#d2cd86; ">(</span>alert_call_count<span style="color:#d2cd86; ">,</span> <span style="color:#008c00; ">1</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> alert <span style="color:#d2cd86; ">=</span> old_alert<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> </pre> <p> Il test sta diventando illegibile, facciamo un primo passo portando il codice di setup nel setup del modulo. In QUnit si possono dichiarare dei moduli che <i>assomigliano</i> agli attributi Setup e TearDown delle Fixture di NUnit. </p> <p> Ecco un esempio di dichiarazione di modulo con i metodi setup e teardown: </p> <pre style="color:#d1d1d1;background:#000000;">module<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">"module name"</span><span style="color:#d2cd86; ">,</span> <span style="color:#b060b0; ">{</span> setup<span style="color:#b060b0; ">:</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#9999a9; ">// setup code</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">,</span> teardown<span style="color:#b060b0; ">:</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#9999a9; ">// teardown code</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span> </pre> <p> Proviamo ad applicare il concetto appena esposto al test precedente: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">var</span> old_alert<span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> alert_call_count <span style="color:#d2cd86; ">=</span> <span style="color:#008c00; ">0</span><span style="color:#b060b0; ">;</span> module<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">"show alert"</span><span style="color:#d2cd86; ">,</span> <span style="color:#b060b0; ">{</span> setup<span style="color:#b060b0; ">:</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> old_alert <span style="color:#d2cd86; ">=</span> alert<span style="color:#b060b0; ">;</span> alert_call_count <span style="color:#d2cd86; ">=</span> <span style="color:#008c00; ">0</span><span style="color:#b060b0; ">;</span> alert <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> alert_call_count<span style="color:#d2cd86; ">++</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">,</span> teardown<span style="color:#b060b0; ">:</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> alert <span style="color:#d2cd86; ">=</span> old_alert<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span> <span style="color:#e66170; font-weight:bold; ">test</span><span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">"show alert"</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> show_alert<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">'Ciao!'</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> equals<span style="color:#d2cd86; ">(</span>alert_call_count<span style="color:#d2cd86; ">,</span> <span style="color:#008c00; ">1</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> </pre> <p> Il test si è accorciato notevolmente, ma se abbiamo mock più complicati il codice del setup diventerebbe presto molto complicato. La logica precedente comunque si puo' estrarre un oggetto Mock in modo da semplificare la scrittura dei test. </p> <p> Per testare il parametro passato si puo' procedere in maniera simile basta salvarsi il valore in una variabile e poi fare la assert su quel valore. </p> <img src="http://blogs.ugidotnet.org/antonioganci/aggbug/99709.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/antonioganci/archive/2011/02/11/scrivere-test-automatici-per-javascript-parte-3.aspx Fri, 11 Feb 2011 15:56:53 GMT http://blogs.ugidotnet.org/antonioganci/archive/2011/02/11/scrivere-test-automatici-per-javascript-parte-3.aspx#feedback 3 http://blogs.ugidotnet.org/antonioganci/comments/commentRss/99709.aspx http://blogs.ugidotnet.org/antonioganci/services/trackbacks/99709.aspx Scrivere test automatici per Javascript - parte 2 http://blogs.ugidotnet.org/antonioganci/archive/2011/02/08/scrivere-test-automatici-per-javascript-parte-2.aspx <p> Nello scorso <a href="http://blogs.ugidotnet.org/AntonioGanci/archive/2011/02/08/scrivere-test-automatici-per-javascript.aspx">post</a> ho descritto come scrivere test automatici per Javascript. Uno degli svantaggi della soluzione proposta sta nel ricordarsi di chiamare le function di test. Infatti se guardiamo il codice della pagina html: </p> <pre style="color:#d1d1d1;background:#000000;"> $<span style="color:#d2cd86; ">(</span>document<span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">.</span>ready<span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">{</span> sum_test<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span> </pre> <p> Vediamo la chiamata a sum_test che contine il test. Se abbiamo molti di questi metodi la manutenzione dell'elenco puo' diventare piuttosto noiosa e error-prone. </p> <p> Una soluzione è quella di creare un oggetto Javascript che esegua automaticamente tutte le function che terminano per _test. </p> <p> In Javascript esiste l'oggetto globale window il quale contiene, tra le altre cose, tutte le function definite dall'utente. Abbiamo quindi sfruttato questa caratteristica per realizzare un test runner di cui riporto il codice. </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> TestRunner<span style="color:#d2cd86; ">(</span>filter<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> test_filter <span style="color:#d2cd86; ">=</span> filter<span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>run <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> tests <span style="color:#d2cd86; ">=</span> test_filter<span style="color:#d2cd86; ">.</span>select_all<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">for</span> <span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">var</span> test_index <span style="color:#e66170; font-weight:bold; ">in</span> tests<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> tests<span style="color:#d2cd86; ">[</span>test_index<span style="color:#d2cd86; ">]</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span> <span style="color:#e66170; font-weight:bold; ">var</span> TestFilter <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span>test_container<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> container <span style="color:#d2cd86; ">=</span> test_container<span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>select_all <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> properties <span style="color:#d2cd86; ">=</span> get_all_accessible_properties<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">return</span> select_test_functions<span style="color:#d2cd86; ">(</span>properties<span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> get_all_accessible_properties <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> result <span style="color:#d2cd86; ">=</span> <span style="color:#d2cd86; ">[</span><span style="color:#d2cd86; ">]</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">for</span> <span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">var</span> property_name <span style="color:#e66170; font-weight:bold; ">in</span> container<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">if</span><span style="color:#d2cd86; ">(</span>is_property_accessible<span style="color:#d2cd86; ">(</span>property_name<span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> result<span style="color:#d2cd86; ">.</span>push<span style="color:#d2cd86; ">(</span>container<span style="color:#d2cd86; ">[</span>property_name<span style="color:#d2cd86; ">]</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span> <span style="color:#e66170; font-weight:bold; ">return</span> result<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> select_test_functions <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span>properties<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> result <span style="color:#d2cd86; ">=</span> <span style="color:#d2cd86; ">[</span><span style="color:#d2cd86; ">]</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">for</span> <span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">var</span> property_index <span style="color:#e66170; font-weight:bold; ">in</span> properties<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> property <span style="color:#d2cd86; ">=</span> properties<span style="color:#d2cd86; ">[</span>property_index<span style="color:#d2cd86; ">]</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">if</span><span style="color:#d2cd86; ">(</span>is_test_function<span style="color:#d2cd86; ">(</span>property<span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> result<span style="color:#d2cd86; ">.</span>push<span style="color:#d2cd86; ">(</span>property<span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span> <span style="color:#e66170; font-weight:bold; ">return</span> result<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> is_property_accessible <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span>property_name<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">try</span> <span style="color:#b060b0; ">{</span> container<span style="color:#d2cd86; ">[</span>property_name<span style="color:#d2cd86; ">]</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">return</span> <span style="color:#0f4d75; ">true</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#e66170; font-weight:bold; ">catch</span><span style="color:#d2cd86; ">(</span>exc<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">return</span> <span style="color:#0f4d75; ">false</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">var</span> is_test_function <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span>property<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">return</span> <span style="color:#e66170; font-weight:bold; ">typeof</span> property <span style="color:#d2cd86; ">===</span> <span style="color:#00c4c4; ">'function'</span> <span style="color:#d2cd86; ">&amp;&amp;</span> property<span style="color:#d2cd86; ">.</span><span style="color:#e66170; font-weight:bold; ">toString</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">.</span><span style="color:#e66170; font-weight:bold; ">indexOf</span><span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">'_test()'</span><span style="color:#d2cd86; ">)</span> <span style="color:#d2cd86; ">&gt;=</span> <span style="color:#008c00; ">0</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span><span style="color:#b060b0; ">;</span> </pre> <p> Per invocare i test basta sostituire la precedente chiamata a sum_test con: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">new</span> TestRunner<span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">new</span> TestFilter<span style="color:#d2cd86; ">(</span>window<span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">.</span>run<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> </pre> <p> Una cosa interessante del codice precedente è che mostra una tecnica (non l'unica possibile) per definire gli oggetti in Javascript. Prendiamo ad esempio il TestRunner. Il codice: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> TestRunner<span style="color:#d2cd86; ">(</span>filter<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#b060b0; ">}</span> </pre> <p> Definisce un oggetto chiamato TestRunner con un costruttore con un parametro. Il quale si puo' instanziare con una sintassi molto simile al C# </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">new</span> TestFilter<span style="color:#d2cd86; ">(</span>someParameter<span style="color:#d2cd86; ">)</span> </pre> <p> All'interno dell'oggetto si possono definire dei field privati. Nel nostro caso aggiungiamo il field test_filter inizializzato con il valore passato dal costruttore: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> TestRunner<span style="color:#d2cd86; ">(</span>filter<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> test_filter <span style="color:#d2cd86; ">=</span> filter<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> </pre> <p> A questo punto possiamo aggiungere un metodo pubblico: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> TestRunner<span style="color:#d2cd86; ">(</span>filter<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> test_filter <span style="color:#d2cd86; ">=</span> filter<span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">this</span><span style="color:#d2cd86; ">.</span>run <span style="color:#d2cd86; ">=</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#9999a9; ">// do something</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span> <span style="color:#ffffff; background:#dd0000; ">}</span> </pre> <p> Per i metodi privati la tecnica è analoga con l'unica differenza di mettere var al posto di this. come si vede per l'oggetto TestFilter. </p> <p> Rimane un ultimo problema da risolvere. Se un test di QUnit solleva un'eccezione non vedo la barra rossa. Per evitare questa mancanza possiamo modificare il codice precedente con questo: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#d2cd86; ">&lt;</span>script type<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"text/javascript"</span><span style="color:#d2cd86; ">&gt;</span> $<span style="color:#d2cd86; ">(</span>document<span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">.</span>ready<span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">try</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">new</span> TestRunner<span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">new</span> TestFilter<span style="color:#d2cd86; ">(</span>window<span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">.</span>run<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#e66170; font-weight:bold; ">catch</span> <span style="color:#d2cd86; ">(</span>e<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> module<span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">"Fatal errors"</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">test</span><span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">"Exception thrown by running tests"</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> ok<span style="color:#d2cd86; ">(</span><span style="color:#0f4d75; ">false</span><span style="color:#d2cd86; ">,</span> <span style="color:#00c4c4; ">'Message: '</span> <span style="color:#d2cd86; ">+</span> e<span style="color:#d2cd86; ">.</span>message <span style="color:#d2cd86; ">+</span> <span style="color:#00c4c4; ">' -- StackTrace: '</span> <span style="color:#d2cd86; ">+</span> e<span style="color:#d2cd86; ">.</span>stack<span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> </pre> <p> A questo punto siamo pronti per scrivere i nostri test e vederli eseguiti all'interno del browser. Buona barra verde! </p><img src="http://blogs.ugidotnet.org/antonioganci/aggbug/99696.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/antonioganci/archive/2011/02/08/scrivere-test-automatici-per-javascript-parte-2.aspx Tue, 08 Feb 2011 15:54:38 GMT http://blogs.ugidotnet.org/antonioganci/archive/2011/02/08/scrivere-test-automatici-per-javascript-parte-2.aspx#feedback 1 http://blogs.ugidotnet.org/antonioganci/comments/commentRss/99696.aspx http://blogs.ugidotnet.org/antonioganci/services/trackbacks/99696.aspx Scrivere test automatici per Javascript http://blogs.ugidotnet.org/antonioganci/archive/2011/02/08/scrivere-test-automatici-per-javascript.aspx <p> Ultimamente sto lavorando con il linguaggio Javascript. All'inizio ho avuto qualche difficoltà, perché la sintassi è molto lontana da quella dei linguaggi con cui ho sviluppato in passato o sviluppo abitualmente (C#, C++, Java), ma con il tempo ha iniziato a piacermi, soprattutto per la semplicità e potenza espressiva. </p> <p> L'attività che sto svolgendo è la copertura di test di codice esistente e un refactoring per migliorarne la leggibilità, in modo da poter aggiungere funzionalità limitando la probabilità di regressioni. </p> <p> Per i test automatici utilizziamo <a href="http://docs.jquery.com/QUnit">QUnit</a>. Vediamo un esempio. Supponiamo di avere il file sum.js con il seguente metodo da testare: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> sum<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">var</span> total <span style="color:#d2cd86; ">=</span> <span style="color:#008c00; ">0</span><span style="color:#b060b0; ">;</span> <span style="color:#e66170; font-weight:bold; ">for</span><span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">var</span> arg <span style="color:#e66170; font-weight:bold; ">in</span> arguments<span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> total <span style="color:#d2cd86; ">+=</span> arguments<span style="color:#d2cd86; ">[</span>arg<span style="color:#d2cd86; ">]</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> <span style="color:#e66170; font-weight:bold; ">return</span> total<span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> </pre> <p> arguments è una variabile di Javascript che contiene i parametri passati alla function. In pratica viene fatta la somma dei parametri passati. </p> <p> Partiamo dal test che dimostra che senza parametri la somma sia zero. Il test lo scriviamo nel file sum-test.js. </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#e66170; font-weight:bold; ">function</span> sum_test<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> <span style="color:#e66170; font-weight:bold; ">test</span><span style="color:#d2cd86; ">(</span><span style="color:#00c4c4; ">"sum without arguments is zero"</span><span style="color:#d2cd86; ">,</span> <span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span> <span style="color:#b060b0; ">{</span> equals<span style="color:#d2cd86; ">(</span>sum<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">,</span> <span style="color:#008c00; ">0</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span> </pre> <p> la function test e equals sono definiti in QUnit. </p> <p> A questo punto creiamo una pagina html che permetta di eseguire il nostro test: </p> <pre style="color:#d1d1d1;background:#000000;"><span style="color:#008073; ">&lt;!</span><span style="color:#008073; ">DOCTYPE</span> <span style="color:#008073; ">html</span> <span style="color:#e66170; font-weight:bold; ">PUBLIC</span> <span style="color:#00c4c4; ">"-//W3C//DTD XHTML 1.0 Transitional//EN"</span> <span style="color:#00c4c4; ">"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"</span><span style="color:#008073; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">html</span> <span style="color:#00dddd; ">xmlns</span><span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00dddd; ">http</span><span style="color:#b060b0; ">:</span><span style="color:#e66170; font-weight:bold; ">//</span><span style="color:#6070ec; ">www.w3.org</span><span style="color:#40015a; ">/1999/xhtml</span><span style="color:#00c4c4; ">"</span> <span style="color:#ff8906; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">head</span><span style="color:#ff8906; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">script</span> type<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">text/javascript</span><span style="color:#00c4c4; ">"</span> src<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00dddd; ">http</span><span style="color:#b060b0; ">:</span><span style="color:#e66170; font-weight:bold; ">//</span><span style="color:#6070ec; ">code.jquery.com</span><span style="color:#40015a; ">/jquery-latest.js</span><span style="color:#00c4c4; ">"</span><span style="color:#ff8906; ">&gt;</span><span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">script</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">link</span> rel<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">stylesheet</span><span style="color:#00c4c4; ">"</span> href<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00dddd; ">http</span><span style="color:#b060b0; ">:</span><span style="color:#e66170; font-weight:bold; ">//</span><span style="color:#6070ec; ">code.jquery.com</span><span style="color:#40015a; ">/qunit/git/qunit.css</span><span style="color:#00c4c4; ">"</span> type<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">text/css</span><span style="color:#00c4c4; ">"</span> media<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#007d45; ">screen</span><span style="color:#00c4c4; ">"</span> <span style="color:#ff8906; ">/&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">script</span> type<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">text/javascript</span><span style="color:#00c4c4; ">"</span> src<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00dddd; ">http</span><span style="color:#b060b0; ">:</span><span style="color:#e66170; font-weight:bold; ">//</span><span style="color:#6070ec; ">code.jquery.com</span><span style="color:#40015a; ">/qunit/git/qunit.js</span><span style="color:#00c4c4; ">"</span><span style="color:#ff8906; ">&gt;</span><span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">script</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">script</span> type<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">text/javascript</span><span style="color:#00c4c4; ">"</span> src<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#40015a; ">sum.js</span><span style="color:#00c4c4; ">"</span><span style="color:#ff8906; ">&gt;</span><span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">script</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">script</span> type<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">text/javascript</span><span style="color:#00c4c4; ">"</span> src<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#40015a; ">sum-test.js</span><span style="color:#00c4c4; ">"</span><span style="color:#ff8906; ">&gt;</span><span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">script</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">script</span> type<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">text/javascript</span><span style="color:#00c4c4; ">"</span> <span style="color:#ff8906; ">&gt;</span> $<span style="color:#d2cd86; ">(</span>document<span style="color:#d2cd86; ">)</span><span style="color:#d2cd86; ">.</span>ready<span style="color:#d2cd86; ">(</span><span style="color:#e66170; font-weight:bold; ">function</span><span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">{</span> sum_test<span style="color:#d2cd86; ">(</span><span style="color:#d2cd86; ">)</span><span style="color:#b060b0; ">;</span> <span style="color:#b060b0; ">}</span><span style="color:#d2cd86; ">)</span> <span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">script</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">title</span><span style="color:#ff8906; ">&gt;</span>Test<span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">title</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">head</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">body</span><span style="color:#ff8906; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">h1</span> id<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">qunit-header</span><span style="color:#00c4c4; ">"</span><span style="color:#ff8906; ">&gt;</span>QUnit example<span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">h1</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">h2</span> id<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">qunit-banner</span><span style="color:#00c4c4; ">"</span><span style="color:#ff8906; ">&gt;</span><span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">h2</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">div</span> id<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">qunit-testrunner-toolbar</span><span style="color:#00c4c4; ">"</span><span style="color:#ff8906; ">&gt;</span><span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">div</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">h2</span> id<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">qunit-userAgent</span><span style="color:#00c4c4; ">"</span><span style="color:#ff8906; ">&gt;</span><span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">h2</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">ol</span> id<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">qunit-tests</span><span style="color:#00c4c4; ">"</span><span style="color:#ff8906; ">&gt;</span><span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">ol</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#ff8906; ">&lt;</span><span style="color:#e66170; font-weight:bold; ">div</span> id<span style="color:#d2cd86; ">=</span><span style="color:#00c4c4; ">"</span><span style="color:#00c4c4; ">qunit-fixture</span><span style="color:#00c4c4; ">"</span><span style="color:#ff8906; ">&gt;</span>test markup, will be hidden<span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">div</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">body</span><span style="color:#fb8400; ">&gt;</span> <span style="color:#fb8400; ">&lt;/</span><span style="color:#e66170; font-weight:bold; ">html</span><span style="color:#fb8400; ">&gt;</span> </pre> <p> Se apriamo la pagina l'output sarà simile a: </p> <p><img src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/AntonioGanci/1890/o_qunit.png" alt="qunit output" /></p> <p>Dalla quale si puo' vedere il test che ha girato. Una cosa interessante è che QUnit mostra il numero delle assert eseguite non solo dei test.</p> <img src="http://blogs.ugidotnet.org/antonioganci/aggbug/99694.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/antonioganci/archive/2011/02/08/scrivere-test-automatici-per-javascript.aspx Tue, 08 Feb 2011 09:47:05 GMT http://blogs.ugidotnet.org/antonioganci/archive/2011/02/08/scrivere-test-automatici-per-javascript.aspx#feedback 2 http://blogs.ugidotnet.org/antonioganci/comments/commentRss/99694.aspx http://blogs.ugidotnet.org/antonioganci/services/trackbacks/99694.aspx Togliere la dipendenza circolare tra due oggetti http://blogs.ugidotnet.org/antonioganci/archive/2010/09/18/togliere-la-dipendenza-circolare-tra-due-oggetti.aspx <p> Supponete di avere due oggetti uno di tipo A e l'altro di tipo B, dove A chiama un metodo di B e viceversa. In pratica esiste una dipendenza circolare tra i due oggetti (il discorso si puo' ampliare facilmente ad n oggetti). </p> <p> Proviamo a visualizzare tale interazione con un communication diagram (ne avevo già parlato in questo <a href="http://blogs.ugidotnet.org/AntonioGanci/archive/2010/07/23/imparare-a-pensare-ad-oggetti.aspx">post</a>). </p> <p> <img src="http://blogs.ugidotnet.org/images/blogs_ugidotnet_org/AntonioGanci/1890/o_Toglierereferenzacircolare.png" alt="referenza circolare" /> </p> <p> Come vedete dal disegno il refactoring risulta molto semplice da capire. In pratica creiamo un nuovo oggetto di tipo C che chiama gli oggetti di tipo A e tipo B ed in questo modo abbiamo tolto la referenza circolare. </p> <p> Non so se esiste già da qualche parte tale refactoring che battezzo: <i>Remove circular dependency</i>. </p> <img src="http://blogs.ugidotnet.org/antonioganci/aggbug/99225.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/antonioganci/archive/2010/09/18/togliere-la-dipendenza-circolare-tra-due-oggetti.aspx Sat, 18 Sep 2010 18:38:41 GMT http://blogs.ugidotnet.org/antonioganci/archive/2010/09/18/togliere-la-dipendenza-circolare-tra-due-oggetti.aspx#feedback 3 http://blogs.ugidotnet.org/antonioganci/comments/commentRss/99225.aspx http://blogs.ugidotnet.org/antonioganci/services/trackbacks/99225.aspx Un tecnica per testare l'interazione tra oggetti http://blogs.ugidotnet.org/antonioganci/archive/2010/09/06/un-tecnica-per-testare-linterazione-tra-oggetti.aspx <p> Ogni tanto, nello sviluppo software, emerge qualche <i>meme</i> come ad esempio: tutte le dipendenze devono essere disaccoppiate tramite un interface, tutte gli oggetti devono essere creati tramite factory, l'accesso ad un database deve avvenire tramite un ORM, il TDD genera un buon design ecc. </p> <p> Cosa hanno in comune tutte le frasi precedenti? Semplice: <b>creano scorciatoie per evitare di pensare</b>. Sarebbe bello se potessimo scrivere codice seguendo alla lettera un manuale, ma sarebbe anche terribilmente noioso e probabilmente verremmo sostituiti da qualche tipo di bot. </p> <p> Prendiamo la prima affermazione: <i>tutte le dipendenze devono essere disaccoppiate tramite un interface</i> e cerchiamo di capire da dove nasce questa esigenza. Il vantaggio di avere le dipendenze solo tramite interfacce <i>dovrebbe</i> essere quello di rendere più testabile le nostre classi. Ma è l'unico modo? Ed è il più semplice? </p> <p> Proviamo a fare un esempio. Supponiamo di voler testare il metodo SayHello: </p> <pre style="color:#000000;background:#ffffff;">var display = <span style="color:#000084; font-weight:bold; ">new</span> Display(); var greeting = <span style="color:#000084; font-weight:bold; ">new</span> Greeting(display); greeting.SayHello(); </pre> <p> L'implementazione di Greeting è la seguente: </p> <pre style="color:#000000;background:#ffffff;"><span style="color:#000084; font-weight:bold; ">public</span> <span style="color:#000084; font-weight:bold; ">class</span> Greeting { <span style="color:#000084; font-weight:bold; ">private</span> <span style="color:#000084; font-weight:bold; ">readonly</span> Display _display; <span style="color:#000084; font-weight:bold; ">public</span> Greeting(Display display) { _display = display; } <span style="color:#000084; font-weight:bold; ">public</span> <span style="color:#000084; font-weight:bold; ">void</span> SayHello() { _display.Show(<span style="color:#0000ff; ">"</span><span style="color:#0000ff; ">Hello!</span><span style="color:#0000ff; ">"</span>); } } </pre> <p> Mentre l'implementazione di display è la seguente: </p> <pre style="color:#000000;background:#ffffff;"><span style="color:#000084; font-weight:bold; ">public</span> <span style="color:#000084; font-weight:bold; ">class</span> Display { <span style="color:#000084; font-weight:bold; ">public</span> <span style="color:#000084; font-weight:bold; ">void</span> Show(<span style="color:#000084; font-weight:bold; ">string</span> text) { Console.WriteLine(text); } } </pre> <p> Sembra proprio il tipico esempio da manuale in cui si estrae l'interfaccia IDisplay e tramite la libreria di mocking preferita testo le interazioni di Greeting con Display. Esiste un'alternativa? </p> <p> La classe Console eredita da TextWriter, anche la classe StringWriter eredita da TextWriter. Proviamo quindi a passare la Console in costruzione a Display: </p> <pre style="color:#000000;background:#ffffff;"><span style="color:#000084; font-weight:bold; ">public</span> <span style="color:#000084; font-weight:bold; ">class</span> Display { <span style="color:#000084; font-weight:bold; ">private</span> <span style="color:#000084; font-weight:bold; ">readonly</span> TextWriter _textWriter; <span style="color:#000084; font-weight:bold; ">public</span> Display(TextWriter textWriter) { _textWriter = textWriter; } <span style="color:#000084; font-weight:bold; ">public</span> <span style="color:#000084; font-weight:bold; ">void</span> Show(<span style="color:#000084; font-weight:bold; ">string</span> text) { _textWriter.WriteLine(text); } } </pre> <p> Ora modfichiamo il main: </p> <pre style="color:#000000;background:#ffffff;">var display = <span style="color:#000084; font-weight:bold; ">new</span> Display(Console.Out); var greeting = <span style="color:#000084; font-weight:bold; ">new</span> Greeting(display); greeting.SayHello(); </pre> <p> A questo punto possiamo scrivere il test: </p> <pre style="color:#000000;background:#ffffff;">var stringWriter = <span style="color:#000084; font-weight:bold; ">new</span> StringWriter(); var greeting = <span style="color:#000084; font-weight:bold; ">new</span> Greeting(<span style="color:#000084; font-weight:bold; ">new</span> Display(stringWriter)); greeting.SayHello(); Assert.That(stringWriter.ToString(), Is.EqualTo(<span style="color:#0000ff; ">"</span><span style="color:#0000ff; ">Hello!</span><span style="color:#0000ff; ">"</span>)); </pre> <p> In questo modo abbiamo fatto <b>un test più solido rispetto a testare l'interazione con un interfaccia</b> ed il codice è più semplice. </p> <img src="http://blogs.ugidotnet.org/antonioganci/aggbug/99157.aspx" width="1" height="1" /> Antonio Ganci http://blogs.ugidotnet.org/antonioganci/archive/2010/09/06/un-tecnica-per-testare-linterazione-tra-oggetti.aspx Mon, 06 Sep 2010 09:54:57 GMT http://blogs.ugidotnet.org/antonioganci/archive/2010/09/06/un-tecnica-per-testare-linterazione-tra-oggetti.aspx#feedback 4 http://blogs.ugidotnet.org/antonioganci/comments/commentRss/99157.aspx http://blogs.ugidotnet.org/antonioganci/services/trackbacks/99157.aspx