{"id":382,"date":"2013-06-05T15:58:36","date_gmt":"2013-06-05T13:58:36","guid":{"rendered":"https:\/\/alistapart.com\/it\/article\/scrivere-javascript-testabile\/"},"modified":"2013-06-05T15:58:36","modified_gmt":"2013-06-05T13:58:36","slug":"scrivere-javascript-testabile","status":"publish","type":"article","link":"https:\/\/alistapart.com\/it\/article\/scrivere-javascript-testabile\/","title":{"rendered":"Scrivere JavaScript testabile"},"content":{"rendered":"<div class=\"paragrafo\">\n<p><img loading=\"lazy\" decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2013\/06\/n75aweb.png\" border=\"0\" width=\"250\" height=\"156\" style=\"float: left; border: 0px;\" \/>Ci siamo passati tutti: quel pezzo di codice JavaScript che era cominciato come una manciata di righe cresce fino ad una dozzina, poi a due dozzine e cos\u00ec via. Durante l&#8217;avanzamento, una funzione assume qualche altro argomento, ad un conditional vengono aggiunte altre condizioni. E poi un giorno, arriva il bug report: qualcosa non funziona e tocca a noi sbrogliare la matassa.<\/p>\n<p>Chiedendo al nostro codice client side di assumersi sempre maggiori responsabilit\u00e0 &#8211; seriamente, al giorno d&#8217;oggi intere applicazioni vivono per lo pi\u00f9 nel browser &#8211; due cose appaiono chiare: una, non possiamo solo cliccare per tutta l&#8217;applicazione per testare che le cose funzionino come ci aspettiamo, i test automatici sono cruciali per avere fiducia nel nostro codice; due, probabilmente dovremo cambiare il modo in cui scriviamo il nostro codice per rendere possibile la stesura di test.<\/p>\n<p>Abbiamo davvero bisogno di cambiare il modo in cui programmiamo? S\u00ec, perch\u00e9 anche se sappiamo che i test automatici sono una buona cosa, la maggior parte di noi probabilmente \u00e8 solo in grado di scrivere degli &#8220;integration test&#8221;. Questi ultimi sono preziosi perch\u00e9 si focalizzano sul modo in cui i pezzi di un&#8217;applicazione funzionano insieme, ma quello che non fanno \u00e8 dirci se una singola <em>unit\u00e0 di funzionalit\u00e0<\/em> si sta comportando come dovrebbe.<\/p>\n<p>Qui \u00e8 dove entrano in gioco gli &#8220;unit test&#8221; e faremo davvero fatica a <em>scrivere degli unit test<\/em> finch\u00e9 non cominceremo a <em>scrivere JavaScript testabile<\/em>.<\/p>\n<\/div>\n<div class=\"paragrafo\">\n<h2>Unit vs. integration: qual \u00e8 la differenza?<\/h2>\n<p>Scrivere degli integration test solitamente \u00e8 piuttosto facile: scriviamo semplicemente del codice che descrive il modo in cui un utente interagisce con la nostra app e cosa dovrebbe aspettarsi di vedere l&#8217;utente durante tale interazione. <a href=\"http:\/\/docs.seleniumhq.org\/\">Selenium<\/a> \u00e8 un tool popolare per automatizzare i browser. <a href=\"https:\/\/github.com\/jnicklas\/capybara\">Capybara<\/a> per Ruby rende semplice parlare a Selenium e ci sono molti altri tool anche per altri linguaggi.<\/p>\n<p>Ecco un integration test per una porzione di una app di ricerca:<\/p>\n<pre><code class=\"language-javascript\">def test_search\n  fill_in('q', :with =&gt; 'cat')\n  find('.btn').click\n  assert( find('#results li').has_content?('cat'), 'Search results are shown' )\n  assert( page.has_no_selector?('#results li.no-results'), 'No results is not shown' )\nend<\/code><\/pre>\n<p>Laddove un integration test \u00e8 interessato all&#8217;interazione dell&#8217;utente con una app, uno unit test \u00e8 strettamente interessato a una piccola porzione del codice:<\/p>\n<blockquote>\n<p>Quando richiamo una funzione con un certo input, ricevo l&#8217;output atteso?<\/p>\n<\/blockquote>\n<p>Le app scritte nel tradizionale stile procedurale possono essere molto difficili da testare con lo unit test &#8211; e anche difficili da mantenere, debuggare ed estendere. Ma se scriviamo il codice con in mente le necessit\u00e0 del nostro futuro unit test, non solo troveremo che scrivere i test diventa pi\u00f9 semplice di quello che ci aspetteremmo, ma anche che chiaramente <em>scriveremo del codice migliore<\/em>.<\/p>\n<p>Per capire di cosa sto parlando, diamo un&#8217;occhiata a una semplice app di ricerca:<\/p>\n<div class=\"illustration full left\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2013\/06\/app.png\" border=\"0\" alt=\"Srchr\" width=\"100%\" style=\"border: 0px;\" \/><\/div>\n<p>Quando un utente inserisce un termine di ricerca, la app manda una XHR al server per i dati corrispondenti. Quando il server risponde con i dati, formattati come JSON, l&#8217;app prende quei dati e li mostra sulla pagina, usando un templating client side. Un utente pu\u00f2 cliccare su un risultato di ricerca per indicare che gli piace (un &#8220;like&#8221;): quando questo avviene, il nome della persona a cui ha dato il &#8220;like&#8221; viene aggiunta alla lista dei &#8220;Liked&#8221; sulla destra.<\/p>\n<p>Un&#8217;implementazione JavaScript &#8220;tradizionale&#8221; di questa app potrebbe essere la seguente:<\/p>\n<pre><code class=\"language-javascript\">var tmplCache = {};\n\nfunction loadTemplate (name) {\n  if (!tmplCache[name]) {\n    tmplCache[name] = $.get('\/templates\/' + name);\n  }\n  return tmplCache[name];\n}\n\n$(function () {\n\n  var resultsList = $('#results');\n  var liked = $('#liked');\n  var pending = false;\n\n  $('#searchForm').on('submit', function (e) {\n    e.preventDefault();\n\n    if (pending) { return; }\n\n    var form = $(this);\n    var query = $.trim( form.find('input[name=\"q\"]').val() );\n\n    if (!query) { return; }\n\n    pending = true;\n\n    $.ajax('\/data\/search.json', {\n      data : { q: query },\n      dataType : 'json',\n      success : function (data) {\n        loadTemplate('people-detailed.tmpl').then(function (t) {\n          var tmpl = _.template(t);\n          resultsList.html( tmpl({ people : data.results }) );\n          pending = false;\n        });\n      }\n    });\n\n    $('&lt;li&gt;', {\n      'class' : 'pending',\n      html : 'Searching &amp;hellip;'\n    }).appendTo( resultsList.empty() );\n  });\n\n  resultsList.on('click', '.like', function (e) {\n    e.preventDefault();\n    var name = $(this).closest('li').find('h2').text();\n    liked.find('.no-results').remove();\n    $('&lt;li&gt;', { text: name }).appendTo(liked);\n  });\n\n});<\/code><\/pre>\n<p>Il mio amico <a href=\"https:\/\/twitter.com\/ajpiano\">Adam Sontag<\/a> la chiama codice <cite>Choose Your Own Adventure (&#8220;scegli la tua avventura&#8221;)<\/cite>: su ogni riga potremmo aver a che fare con la presentazione, con i dati, con l&#8217;interazione utente o con lo stato dell&#8217;applicazione. Chi pu\u00f2 dirlo? \u00c8 abbastanza facile scrivere dei test degli integration test per questo tipo di codice, ma \u00e8 difficile testare le singole <em>unit\u00e0 di funzionalit\u00e0<\/em>.<\/p>\n<p>Cosa lo rende difficile? Quattro cose:<\/p>\n<ul>\n<li>Una generale mancanza di struttura: quasi tutto avviene in una callback <code>$(document).ready()<\/code> e poi in funzioni anonime che non possono essere testate perch\u00e9 non sono esposte.<\/li>\n<li>Funzioni complesse: se una funzione \u00e8 di pi\u00f9 di 10 righe, come l&#8217;handler del submit, \u00e8 molto probabile che faccia troppo.<\/li>\n<li>Stati nascosti o condivisi: per esempio, dal momento che <code>pending<\/code> \u00e8 in una closure, non c&#8217;\u00e8 modo di testare che lo stato &#8220;pending&#8221; sia impostato correttamente.<\/li>\n<li>&#8220;Tight coupling&#8221;: per esempio, un handler per il successo <code>$.ajax<\/code> non dovrebbe avere accesso diretto al DOM.<\/li>\n<\/ul>\n<\/div>\n<div class=\"paragrafo\">\n<h2>Organizzare il codice<\/h2>\n<p>Il primo step verso la risoluzione di tutto questo \u00e8 avere un approccio meno aggrovigliato al nostro codice, scomponendolo in poche differenti aree di responsabilit\u00e0:<\/p>\n<ul>\n<li>Presentazione ed interazione<\/li>\n<li>Data management e persistenza<\/li>\n<li>Stato generale dell&#8217;applicazione<\/li>\n<li>Codice di setup e codice per far s\u00ec che i pezzi funzionino assieme<\/li>\n<\/ul>\n<p>Nell&#8217;implementazione &#8220;tradizionale&#8221; mostrata sopra, queste quattro categorie sono mischiate: su una riga gestiamo la presentazione e due righe dopo magari stiamo comunicando con il server.<\/p>\n<div class=\"illustration full left\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2013\/06\/code-lines.png\" border=\"0\" alt=\"Code Lines\" width=\"100%\" \/><\/div>\n<p>Mentre possiamo assolutamente scrivere degli integration test per questo codice &#8211; e dovremmo! &#8211; scrivere degli unit test per questo codice \u00e8 piuttosto difficile. Nei nostri test funzionali, possiamo fare affermazioni come &#8220;quando un utente cerca qualcosa, dovrebbe vedere i risultati appropriati&#8221;, ma non possiamo essere molto pi\u00f9 specifici. Se qualcosa va storto, dovremo trovare esattamente dove c&#8217;\u00e8 stato l&#8217;errore e i nostri test funzionali non ci potranno essere di grande aiuto.<\/p>\n<p>Tuttavia, se ripensiamo il modo in cui scriviamo il nostro codice, possiamo scrivere degli unit test che ci daranno degli insight migliori riguardo a quello che \u00e8 andato storto e anche aiutarci ad avere del codice che sia pi\u00f9 semplice da usare, mantenere ed estendere.<\/p>\n<p>Il nostro nuovo codice seguir\u00e0 alcuni principi guida:<\/p>\n<ul>\n<li>Rappresentare ciascun pezzo distinto di comportamento come un oggetto separato che ricada in una delle quattro aree di responsabilit\u00e0 e non abbia bisogno di sapere nulla degli altri oggetti. Questo ci aiuter\u00e0 ad evitare di creare del codice ingarbugliato.<\/li>\n<li>Supportare la configurabilit\u00e0 piuttosto che le cose &#8220;hard coded&#8221;. Questo ci impedir\u00e0 di replicare tutto il nostro ambiente HTML per poter scrivere i nostri test.<\/li>\n<li>Mantenere i metodi degli oggetti semplici e brevi. Questo ci aiuter\u00e0 ad avere test semplici e codice facilmente leggibile.<\/li>\n<li>Usare funzioni &#8220;constructor&#8221; per creare istanze di oggetti. Questo render\u00e0 possibile la creazione di copie &#8220;pulite&#8221; di ciascun pezzo di codice per il bene del testing.<\/li>\n<\/ul>\n<p>Per cominciare, dobbiamo comprendere come suddividere la nostra applicazione in pezzi differenti. Avremo tre pezzi dedicati alla presentazione e all&#8217;interazione: la Form di Ricerca (Search Form), i Risultati della Ricerca (Search Results) e la Likes Box.<\/p>\n<div class=\"illustration full left\"><img decoding=\"async\" src=\"http:\/\/alistapart.com\/it\/wp-content\/uploads\/sites\/2\/2013\/06\/app-views.png\" border=\"0\" alt=\"Application Views\" width=\"100%\" \/><\/div>\n<p>Avremo anche un pezzo dedicato alla raccolta dati dal server e un pezzo dedicato a tenere tutto unito insieme.<\/p>\n<p>Cominciamo con il guardare uno dei pi\u00f9 semplici pezzi della nostra applicazione: la Likes Box. Nella versione originale dell&#8217;app, questo codice era responsabile dell&#8217;aggiornamento della Likes Box:<\/p>\n<pre><code class=\"language-javascript\">var liked = $('#liked');\n\nvar resultsList = $('#results');\n\n\n\/\/ ...\n\n\nresultsList.on('click', '.like', function (e) {\n  e.preventDefault();\n\n  var name = $(this).closest('li').find('h2').text();\n\n  liked.find( '.no-results' ).remove();\n\n  $('&lt;li&gt;', { text: name }).appendTo(liked);\n\n});<\/code><\/pre>\n<p>Il pezzo dei Risultati della Ricerca (Search Results) \u00e8 completamente intrecciato con il pezzo della Likes Box e ha bisogno di conoscere molto del suo markup. Un approccio molto migliore e pi\u00f9 testabile consiste nel creare un oggetto Likes Box che \u00e8 responsabile della manipolazione del DOM in relazione alla Likes Box:<\/p>\n<pre><code class=\"language-javascript\">var Likes = function (el) {\n  this.el = $(el);\n  return this;\n};\n\nLikes.prototype.add = function (name) {\n  this.el.find('.no-results').remove();\n  $('&lt;li&gt;', { text: name }).appendTo(this.el);\n};<\/code><\/pre>\n<p>Questo codice fornisce una funzione &#8220;constructor&#8221; che crea una nuova istanza di una Likes Box. L&#8217;istanza che viene creata ha un metodo <code>.add()<\/code>, che possiamo usare per aggiungere nuovi risultati. Possiamo scrivere un paio di test per provare che funzioni:<\/p>\n<pre><code class=\"language-javascript\">var ul;\n\nsetup(function(){\n  ul = $('&lt;ul&gt;&lt;li class=\"no-results\"&gt;&lt;\/li&gt;&lt;\/ul&gt;');\n});\n\ntest('constructor', function () {\n  var l = new Likes(ul);\n  assert(l);\n});\n\ntest('adding a name', function () {\n  var l = new Likes(ul);\n  l.add('Brendan Eich');\n\n  assert.equal(ul.find('li').length, 1);\n  assert.equal(ul.find('li').first().html(), 'Brendan Eich');\n  assert.equal(ul.find('li.no-results').length, 0);\n});<\/code><\/pre>\n<p>Non troppo complicato, vero? In questo caso, utilizziamo <a href=\"http:\/\/visionmedia.github.io\/mocha\/\">Mocha<\/a> come <em>framework<\/em> per i test e <a href=\"http:\/\/chaijs.com\/\">Chai<\/a> come <em>assertion library<\/em>. Mocha fornisce le funzioni <code>test<\/code> e <code>setup<\/code>, Chai fornisce <code>assert<\/code>. Ci sono molti altri framework di test e assertion library tra cui scegliere, ma al fine di avere un&#8217;introduzione, trovo che queste due funzionino bene. Dovreste trovarne una che funzioni meglio per voi e per il vostro progetto. Oltre a Mocha, <a href=\"http:\/\/qunitjs.com\/\">QUnit<\/a> \u00e8 popolare e <a href=\"http:\/\/theintern.io\/\">Intern<\/a> \u00e8 un nuovo framework molto promettente.<\/p>\n<p>Il nostro codice per il test comincia con la creazione di un elemento che useremo come container per la nostra Likes Box. Poi, fa due test: uno \u00e8 un &#8220;sanity check&#8221; per essere sicuri di poter fare una Likes Box; l&#8217;altro \u00e8 un test per assicurarsi che il nostro metodo <code>.add()<\/code> ha l&#8217;effetto desiderato. Mettendo in atto questi test, possiamo rifattorizzare in maniera sicura il codice per la nostra Likes Box ed essere sicuri che sapremo se danneggiamo qualcosa.<\/p>\n<p>Il codice della nostra nuova applicazione ha ora questo aspetto:<\/p>\n<pre><code class=\"language-javascript\">var liked = new Likes('#liked');\nvar resultsList = $('#results');\n\n\n\n\/\/ ...\n\n\n\nresultsList.on('click', '.like', function (e) {\n  e.preventDefault();\n\n  var name = $(this).closest('li').find('h2').text();\n\n  liked.add(name);\n});<\/code><\/pre>\n<p>Il pezzo dei Risultati della Ricerca (Search Results) \u00e8 pi\u00f9 complesso della Likes Box, ma facciamo comunque un tentativo di refactoring. Proprio come abbiamo creato un metodo <code>.add()<\/code> sulla Likes Box, vogliamo anche creare dei metodi per interagire con i Risultati della Ricerca. Vorremmo un modo per aggiungere nuovi risultati cos\u00ec come un modo per fare il \u201cbroadcast\u201d al resto dell&#8217;app quando succedono alcune cose all&#8217;interno dei Risultati di Ricerca, per esempio, quando qualcuno mette un like a un risultato.<\/p>\n<pre><code class=\"language-javascript\">var SearchResults = function (el) {\n  this.el = $(el);\n  this.el.on( 'click', '.btn.like', _.bind(this._handleClick, this) );\n};\n\nSearchResults.prototype.setResults = function (results) {\n  var templateRequest = $.get('people-detailed.tmpl');\n  templateRequest.then( _.bind(this._populate, this, results) );\n};\n\nSearchResults.prototype._handleClick = function (evt) {\n  var name = $(evt.target).closest('li.result').attr('data-name');\n  $(document).trigger('like', [ name ]);\n};\n\nSearchResults.prototype._populate = function (results, tmpl) {\n  var html = _.template(tmpl, { people: results });\n  this.el.html(html);\n};<\/code><\/pre>\n<p>Ora, il codice della nostra vecchia app per gestire l&#8217;interazione tra Search Results e Likes Box potrebbe essere questo:<\/p>\n<pre><code class=\"language-javascript\">var liked = new Likes('#liked');\nvar resultsList = new SearchResults('#results');\n\n\n\/\/ ...\n\n\n$(document).on('like', function (evt, name) {\n  liked.add(name);\n})<\/code><\/pre>\n<p>\u00c8 molto pi\u00f9 semplice e meno intricato perch\u00e9 stiamo usando <code>document<\/code> come un message bus globale e passando i messaggi attraverso di esso, cos\u00ec che i componenti individuali non hanno bisogno di sapere gli uni degli altri. (Notate che in una app reale, useremmo qualcosa come <a href=\"http:\/\/backbonejs.org\">Backbone<\/a> o la libreria <a href=\"https:\/\/github.com\/tildeio\/rsvp.js\">RSVP<\/a> per gestire gli eventi. Qui stiamo facendo il triggering su <code>document<\/code> per mantenere semplici le cose). Stiamo anche nascondendo tutto il lavoro sporco, come trovare il nome della persona a cui \u00e8 stato dato il like, all&#8217;interno dell&#8217;oggetto Search Results, piuttosto che sporcare il codice della nostra applicazione. La parte migliore \u00e8 che adesso possiamo scrivere dei test per provare che il nostro oggetto Search Results funzioni come ci aspettiamo:<\/p>\n<pre><code class=\"language-javascript\">var ul;\nvar data = [ \/* fake data here *\/ ];\n\nsetup(function () {\n  ul = $('&lt;ul&gt;&lt;li class=\"no-results\"&gt;&lt;\/li&gt;&lt;\/ul&gt;');\n});\n\ntest('constructor', function () {\n  var sr = new SearchResults(ul);\n  assert(sr);\n});\n\ntest('display received results', function () {\n  var sr = new SearchResults(ul);\n  sr.setResults(data);\n\n  assert.equal(ul.find('.no-results').length, 0);\n  assert.equal(ul.find('li.result').length, data.length);\n  assert.equal(\n    ul.find('li.result').first().attr('data-name'),\n    data[0].name\n  );\n});\n\ntest('announce likes', function() {\n  var sr = new SearchResults(ul);\n  var flag;\n  var spy = function () {\n    flag = [].slice.call(arguments);\n  };\n\n  sr.setResults(data);\n  $(document).on('like', spy);\n\n  ul.find('li').first().find('.like.btn').click();\n\n  assert(flag, 'event handler called');\n  assert.equal(flag[1], data[0].name, 'event handler receives data' );\n});<\/code><\/pre>\n<p>L&#8217;interazione con il server \u00e8 un altro pezzo interessante da considerare. Il codice originale includeva una richiesta diretta <code>$.ajax()<\/code> e la callback interagiva direttamente con il DOM:<\/p>\n<pre><code class=\"language-javascript\">$.ajax('\/data\/search.json', {\n  data : { q: query },\n  dataType : 'json',\n  success : function( data ) {\n    loadTemplate('people-detailed.tmpl').then(function(t) {\n      var tmpl = _.template( t );\n      resultsList.html( tmpl({ people : data.results }) );\n      pending = false;\n    });\n  }\n});<\/code><\/pre>\n<p>Di nuovo, \u00e8 difficile scrivere uno unit test per questo, perch\u00e9 succedono cos\u00ec tante cose in poche righe di codice. Possiamo ristrutturare la porzione di dati della nostra applicazione come un oggetto a s\u00e9 stante:<\/p>\n<pre><code class=\"language-javascript\">var SearchData = function () { };\n\nSearchData.prototype.fetch = function (query) {\n  var dfd;\n\n  if (!query) {\n    dfd = $.Deferred();\n    dfd.resolve([]);\n    return dfd.promise();\n  }\n\n  return $.ajax( '\/data\/search.json', {\n    data : { q: query },\n    dataType : 'json'\n  }).pipe(function( resp ) {\n    return resp.results;\n  });\n};<\/code><\/pre>\n<p>Ora, possiamo cambiare il nostro codice per ottenere i risultati nella pagina:<\/p>\n<pre><code class=\"language-javascript\">var resultsList = new SearchResults('#results');\n\nvar searchData = new SearchData();\n\n\/\/ ...\n\nsearchData.fetch(query).then(resultsList.setResults);<\/code><\/pre>\n<p>Di nuovo, abbiamo incredibilmente semplificato il codice della nostra applicazione ed isolato la complessit\u00e0 all&#8217;interno dell&#8217;oggetto Search Data, piuttosto che averlo &#8220;live&#8221; nel codice principale dell&#8217;applicazione. Abbiamo anche reso testabile l&#8217;interfaccia di ricerca, sebbene ci siano alcune precisazioni da tener presente quando si testa codice che interagisce con il server.<\/p>\n<p>La prima \u00e8 che non vogliamo <em>davvero<\/em> interagire con il server: per farlo dovremmo rientrare nel mondo degli integration test e dal momento che siamo sviluppatori responsabili, abbiamo gi\u00e0 dei test che assicurano che il server faccia la cosa giusta, vera? Al contrario, vogliamo \u201csimulare\u201d l&#8217;interazione con il server, cosa che possiamo fare usando la libreria <a href=\"http:\/\/sinonjs.org\/\">Sinon<\/a>. La seconda avvertenza: dovremmo testare anche i percorsi non ideali, come una empty query.<\/p>\n<pre><code class=\"language-javascript\">test('constructor', function () {\n  var sd = new SearchData();\n  assert(sd);\n});\n\nsuite('fetch', function () {\n  var xhr, requests;\n\n  setup(function () {\n    requests = [];\n    xhr = sinon.useFakeXMLHttpRequest();\n    xhr.onCreate = function (req) {\n      requests.push(req);\n    };\n  });\n\n  teardown(function () {\n    xhr.restore();\n  });\n\n  test('fetches from correct URL', function () {\n    var sd = new SearchData();\n    sd.fetch('cat');\n\n    assert.equal(requests[0].url, '\/data\/search.json?q=cat');\n  });\n\n  test('returns a promise', function () {\n    var sd = new SearchData();\n    var req = sd.fetch('cat');\n\n    assert.isFunction(req.then);\n  });\n\n  test('no request if no query', function () {\n    var sd = new SearchData();\n    var req = sd.fetch();\n    assert.equal(requests.length, 0);\n  });\n\n  test('return a promise even if no query', function () {\n    var sd = new SearchData();\n    var req = sd.fetch();\n\n    assert.isFunction( req.then );\n  });\n\n  test('no query promise resolves with empty array', function () {\n    var sd = new SearchData();\n    var req = sd.fetch();\n    var spy = sinon.spy();\n\n    req.then(spy);\n\n    assert.deepEqual(spy.args[0][0], []);\n  });\n\n  test('returns contents of results property of the response', function () {\n    var sd = new SearchData();\n    var req = sd.fetch('cat');\n    var spy = sinon.spy();\n\n    requests[0].respond(\n      200, { 'Content-type': 'text\/json' },\n      JSON.stringify({ results: [ 1, 2, 3 ] })\n    );\n\n    req.then(spy);\n\n    assert.deepEqual(spy.args[0][0], [ 1, 2, 3 ]);\n  });\n});<\/code><\/pre>\n<p>Per brevit\u00e0, ho tralasciato il refactoring della Search Form e ho anche semplificato alcuni degli altri refactoring e test, ma potete vedere <a href=\"https:\/\/github.com\/rmurphey\/testable-javascript\">qui<\/a> una versione finita dell&#8217;app se siete interessati.<\/p>\n<p>Quando avremo finito di riscrivere la nostra applicazione usando dei pattern di JavaScript testabili, ci ritroveremo con qualcosa di molto pi\u00f9 pulito di quello con cui avevamo cominciato:<\/p>\n<pre><code class=\"language-javascript\">$(function() {\n  var pending = false;\n\n  var searchForm = new SearchForm('#searchForm');\n  var searchResults = new SearchResults('#results');\n  var likes = new Likes('#liked');\n  var searchData = new SearchData();\n\n  $(document).on('search', function (event, query) {\n    if (pending) { return; }\n\n    pending = true;\n\n    searchData.fetch(query).then(function (results) {\n      searchResults.setResults(results);\n      pending = false;\n    });\n\n    searchResults.pending();\n  });\n\n  $(document).on('like', function (evt, name) {\n    likes.add(name);\n  });\n});<\/code><\/pre>\n<p>Tuttavia, ancora pi\u00f9 importante che il codice molto pi\u00f9 pulito della nostra applicazione \u00e8 il fatto che ci ritroviamo una code base che \u00e8 attentamente testata. Questo significa che possiamo fare tranquillamente il refactor su di essa ed aggiungere altro senza la paura di romperne il funzionamento. Possiamo addirittura scrivere nuovi test man mano che troviamo nuove questioni e poi scrivere il codice che passa quei test.<\/p>\n<\/div>\n<div class=\"paragrafo\">\n<h2>Alla lunga, testare rende la vita pi\u00f9 facile<\/h2>\n<p>\u00c8 facile guardare tutto questo e dire: &amp;8220;Aspetta, vuoi che scriva pi\u00f9 codice per fare lo stesso lavoro?\u201d<\/p>\n<p>Il fatto \u00e8 che ci sono alcuni fatti inevitabili nella vita riguardanti Il Fare Cose Su Internet. Passerete del tempo a progettare un approccio per un problema, testerete la vostra soluzione, sia che lo farete cliccando in giro in un browser o scrivendo dei test automatizzati o &#8211; tremate &#8211; lasciando che i vostri utenti testino per voi in produzione. Farete dei cambiamenti al codice e altre persone useranno il vostro codice. Infine, ci saranno dei bug, non importa quanti test scriverete.<\/p>\n<p>La cosa del testing \u00e8 che sebbene richieda un po&#8217; pi\u00f9 di tempo all&#8217;inizio, vi fa davvero risparmiare del tempo a lungo termine. Vi darete delle pacche sulla spalla la prima volta che un test che avete scritto intercetter\u00e0 un bug prima che il codice vada in produzione. Sarete grati, inoltre, quando avrete un sistema che possa provare che il vostro bug fix sitema davvero un bug che si intrufola nel codice.<\/p>\n<\/div>\n<div class=\"paragrafo\">\n<h2>Altre risorse<\/h2>\n<p>Questo articolo tocca solo l&#8217;apice dell&#8217;argomento dei test JavaScript, ma se volete saperne di pi\u00f9, guardate qua:<\/p>\n<ul>\n<li><a href=\"http:\/\/lanyrd.com\/2012\/full-frontal\/sztqh\/\">la mia presentazione<\/a> alla conferenza del 2012 Full Frontal, a Brighton, UK.<\/li>\n<li><a href=\"http:\/\/gruntjs.com\/\">Grunt<\/a>, un tool che aiuta nell&#8217;automazione del processo di testing e molte altre cose.<\/li>\n<li><cite><a href=\"http:\/\/www.amazon.com\/Test-Driven-JavaScript-Development-Developers-Library\/dp\/0321683919\/ref=sr_1_1?ie=UTF8&amp;qid=1366506174&amp;sr=8-1&amp;keywords=test+driven+javascript+development\">Test-Driven JavaScript Development<\/a><\/cite> di Christian Johansen, il creatore della libreria Sinon. \u00c8 un esame complesso ma informativo della pratica del testing JavaScript.<\/li>\n<\/ul>\n<p>Illustrazioni: {carlok}<\/p>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Man mano che JavaScript assume sempre pi\u00f9 responsabilit\u00e0, abbiamo bisogno di una codebase affidabile, che sia accuratamente testata. Gli integration test si concentrano sui modi in cui i pezzi di un&#8217;applicazione lavorano insieme, ma non ci dicono se le unit\u00e0 individuali di funzionalit\u00e0 si comportano come ci aspetteremmo. Qui \u00e8 dove entra in gioco lo unit testing e sar\u00e0 difficile scrivere degli unit test fino a che non scriveremo del JavaScript testabile. Rebecca Murphey ci spiega come risparmiare tempo alla lunga scrivendo del codice per l&#8217;applicazione pi\u00f9 pulito e testando, testando, testando.<\/p>\n","protected":false},"author":818,"featured_media":7000700,"comment_status":"open","ping_status":"open","template":"","categories":[271,92],"tags":[],"coauthors":[393],"class_list":["post-382","article","type-article","status-publish","has-post-thumbnail","hentry","category-javascript","category-numero-75-5-giugno-2013"],"jetpack_sharing_enabled":true,"_links":{"self":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/article\/382","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/article"}],"about":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/types\/article"}],"author":[{"embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/users\/818"}],"replies":[{"embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/comments?post=382"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/media\/7000700"}],"wp:attachment":[{"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/media?parent=382"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/categories?post=382"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/tags?post=382"},{"taxonomy":"author","embeddable":true,"href":"https:\/\/alistapart.com\/it\/wp-json\/wp\/v2\/coauthors?post=382"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}