{"title":"Scrivere la tua prima applicazione in Django, parte 5","version":"4.1","locale":"it","docname":"intro/tutorial05","url":"/it/4.1/intro/tutorial05/","canonical":"https://djangodocs.dev/it/4.1/intro/tutorial05/","summary":"Questo tutorial inizia dove è terminato Tutorial 4 . Abbiamo costruito una applicazione web per i questionari ed adesso per essa creeremo alcuni testi automatici.…","html":"<h1>Scrivere la tua prima applicazione in Django, parte 5<a class=\"heading-anchor\" href=\"#writing-your-first-django-app-part-5\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h1>\n<p>Questo tutorial inizia dove è terminato <a class=\"reference internal\" href=\"/it/4.1/intro/tutorial04/\"><span class=\"doc\">Tutorial 4</span></a> . Abbiamo costruito una applicazione web per i questionari ed adesso per essa creeremo alcuni testi automatici.</p>\n<aside class=\"admonition-where-to-get-help admonition\">\n<p class=\"admonition-title\">Dove trovare aiuto:</p>\n<p>Se hai difficoltà a completare questo tutorial,  per favore vai alla sezione <a class=\"reference internal\" href=\"/it/4.1/faq/help/\"><span class=\"doc\">Getting Help</span></a> delle FAQ.</p>\n</aside>\n<section id=\"introducing-automated-testing\">\n<h2>Introduzione ai test automatici<a class=\"heading-anchor\" href=\"#introducing-automated-testing\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"what-are-automated-tests\">\n<h3>Cosa sono i test automatici?<a class=\"heading-anchor\" href=\"#what-are-automated-tests\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>I test sono routine che controllano il funzionamento del codice.</p>\n<p>Il testing opera a livelli differenti. Alcuni test si posso applicare a piccoli dettagli (<em>un modello particolare restituisce i valori come ci si aspetta?</em>) mentre altri esaminano le operazioni del software a linee più generali (<em>la sequenza di input dell’utente sul sito produce l’output desiderato?</em>). Non è differente dal tipo di test che hai fatto nel  <a class=\"reference internal\" href=\"/it/4.1/intro/tutorial02/\"><span class=\"doc\">Tutorial 2</span></a>, usando la <a class=\"reference internal\" href=\"/it/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> per esaminare il comportamento di un metodo o lanciando l’applicazione ed inserendo i dati per controllare come si comporta.</p>\n<p>La differenza nell” automatizzare i test è che il sistema svolge i test al posto tuo. Tu crei un insieme di test una volta, e ogni volta che effettui una modifica alla tua applicazione, puoi controllare che il codice funzioni come ti aspettavi originariamente, senza dover impiegare tempo a svolgere test manualmente.</p>\n</section>\n<section id=\"why-you-need-to-create-tests\">\n<h3>Perché devi creare dei test<a class=\"heading-anchor\" href=\"#why-you-need-to-create-tests\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Quindi perche creare test, e perche ora?</p>\n<p>Potresti sentire di avere abbastanza da fare solo per imparare Python / Django, e avere ancora un’altra cosa da imparare e da fare può sembrare gravoso e forse non necessario. Dopotutto, la nostra applicazione per i sondaggi ora funziona abbastanza bene; affrontare il problema della creazione di test automatizzati non lo farà funzionare meglio. Se la creazione dell’applicazione sondaggi è l’ultima parte della programmazione Django che farai mai, allora è vero, non hai bisogno di sapere come creare test automatizzati. Ma se non è così, ora è un ottimo momento per imparare.</p>\n<section id=\"tests-will-save-you-time\">\n<h4>I test ti faranno risparmiare tempo<a class=\"heading-anchor\" href=\"#tests-will-save-you-time\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Fino a un certo punto accertarsi che l’app “sembra funzionare” potrebbe essere un test soddisfacente. In applicazioni sofisticate, potresti avere dozzine di complesse interazioni tra i componenti.</p>\n<p>Una modifica in uno di questi componenti potrebbe avere conseguenze inaspettate sul comportamento dell’applicazione.\nControllare che «tutto funzioni» potrebbe voler dire provare le funzionalità del tuo codice con decine di differenti varianti dei tuoi dati di test per essere sicuro di non aver danneggiato nulla con l’ultima modifica - non un bell’impiego del tuo tempo.</p>\n<p>Specialmente quando i test automatici possono fare tutto questo per te in pochi secondi. Se qualcosa va storto, i test ti assisteranno nel trovare il codice che ha causato il comportamento inaspettato.</p>\n<p>A volte, potrebbe sembrare un lavoro che toglie tempo alla tua produttività, dover programmare per affrontare il compito poco affascinante e poco emozionante di scrivere test, soprattutto quando sai che il tuo codice sta funzionando a dovere.</p>\n<p>Tuttavia, scrivere test è molto più soddisfacente che passare ore a testare manualmente l’applicazione o cercare di identificare la causa di un problema appena introdotto.</p>\n</section>\n<section id=\"tests-don-t-just-identify-problems-they-prevent-them\">\n<h4>I test non si limitano a identificare i problemi, ma li prevengono<a class=\"heading-anchor\" href=\"#tests-don-t-just-identify-problems-they-prevent-them\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>È uno sbaglio pensare che i test siano un aspetto negativo dello sviluppo.</p>\n<p>Senza test, il fine o il comportamento atteso di una applicazione potrebbe essere piuttosto opaco. Anche se è il tuo codice, talvolta ti ritroverai a frugarci dentro cercando di capire che cosa fa esattamente.</p>\n<p>I test operano un cambiamento; illuminano il tuo codice dall’interno e quando qualcosa va storto, gettano luce sulla parte che ha fallito – <em>anche quando non ti sei nemmeno accorto che ha fallito</em>.</p>\n</section>\n<section id=\"tests-make-your-code-more-attractive\">\n<h4>I test rendono il tuo codice più attraente<a class=\"heading-anchor\" href=\"#tests-make-your-code-more-attractive\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>Potresti anche aver creato un software brillante ma potresti scoprire che molti altri sviluppatori si rifiutano di dargli uno sguardo perchè manca dei test; senza test, non ci faranno affidamento. Jacob Kaplan-Moss, uno degli sviluppatori originali di Django, dice «Il codice senza test è marcio dalle fondamenta».</p>\n<p>Il fatto che altri sviluppatori vogliano vedere i test nel tuo software prima di prenderlo sul serio è ancora un altro motivo per iniziare a scrivere test.</p>\n</section>\n<section id=\"tests-help-teams-work-together\">\n<h4>I test aiutano i gruppi a lavorare insieme<a class=\"heading-anchor\" href=\"#tests-help-teams-work-together\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h4>\n<p>I punti precedenti sono scritti dal punto di vista di un solo sviluppatore che mantiene una applicazione. Applicazioni complesse saranno manutenute da team. I test garantiscono che i colleghi non rompano inavvertitamente il codice (e che tu non danneggi il loro senza volerlo). Se vuoi vivere della programmazione Django, devi essere bravo a scrivere test!</p>\n</section>\n</section>\n</section>\n<section id=\"basic-testing-strategies\">\n<h2>Strategie basilari di test<a class=\"heading-anchor\" href=\"#basic-testing-strategies\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Ci sono tanti modi per scrivere i test.</p>\n<p>Alcuni programmatori seguono una disciplina chiamata «<a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Test-driven_development\">test-driven development</a>»; scrivono test anche prima di scrivere il codice. Può sembrare una cosa controintuitiva ma in effetti è simile a quel che molte persone farebbero in ogni caso; descrivono un problema, poi creano del codice per risolverlo. Il test-driven development formalizza il problema in un test case Python.</p>\n<p>Molto più spesso, un principiante del testing creerà un po” di codice e poi deciderà che debba avere dei test. Magari sarebbe stato meglio scrivere alcuni test prima ma non è mai troppo tardi per iniziare.</p>\n<p>A volte è difficile capire da dove cominciare per scrivere dei test. Se hai scritto molte centinaia di righe di Python, scegliere qualcosa da testare può non essere semplice. In questi casi, puoi scrivere il tuo primo test la prossima volta che apporti un cambiamento, che sia aggiungere una nuova feature o risolvere un bug.</p>\n<p>Quindi facciamo le cose in maniera giusta.</p>\n</section>\n<section id=\"writing-our-first-test\">\n<h2>Scrivere il nostro primo test<a class=\"heading-anchor\" href=\"#writing-our-first-test\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<section id=\"we-identify-a-bug\">\n<h3>Identifichiamo un bug<a class=\"heading-anchor\" href=\"#we-identify-a-bug\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Fortunatamente, c’è un piccolo bug nell’applicazione <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code> che possiamo risolvere: il metodo <code class=\"docutils literal notranslate\"><span class=\"pre\">Question.was_published_recently()</span></code> restituisce <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> se <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> è stata pubblicata entro un giorno (che è corretto) ma anche se il campo <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> di <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> è futuro (che certamente non va bene).</p>\n<p>Conferma il bug usando la <a class=\"reference internal\" href=\"/it/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> per controllare il metodo su una domanda la cui data è futura:</p>\n<div class=\"console\" data-console><div class=\"console-panel\" data-platform=\"unix\"><p class=\"console-label\" id=\"console-0-unix-label\">Linux / macOS</p><div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Shell code\"><code><span class=\"gp\">$ </span>python<span class=\"w\"> </span>manage.py<span class=\"w\"> </span>shell\n</code></pre></div>\n</div><div class=\"console-panel\" data-platform=\"windows\"><p class=\"console-label\" id=\"console-0-windows-label\">Windows</p><div class=\"code-block\" data-language=\"doscon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Windows</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Windows shell\"><code><span class=\"gp\">...\\&gt;</span> py manage.py shell\n</code></pre></div></div></div>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">datetime</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.utils</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">timezone</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">polls.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Question</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># create a Question instance with pub_date 30 days in the future</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">future_question</span> <span class=\"o\">=</span> <span class=\"n\">Question</span><span class=\"p\">(</span><span class=\"n\">pub_date</span><span class=\"o\">=</span><span class=\"n\">timezone</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span> <span class=\"o\">+</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">timedelta</span><span class=\"p\">(</span><span class=\"n\">days</span><span class=\"o\">=</span><span class=\"mi\">30</span><span class=\"p\">))</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># was it published recently?</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">future_question</span><span class=\"o\">.</span><span class=\"n\">was_published_recently</span><span class=\"p\">()</span>\n<span class=\"go\">True</span>\n</code></pre></div>\n<p>Siccome le cose nel futuro non sono “recenti”, questo è chiaramente sbagliato.</p>\n</section>\n<section id=\"create-a-test-to-expose-the-bug\">\n<h3>Creare un test per esporre un bug<a class=\"heading-anchor\" href=\"#create-a-test-to-expose-the-bug\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Quel che abbiamo appena fatto nella <a class=\"reference internal\" href=\"/it/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> per testare il problema è esattamente quel che facciamo nel nostro test automatizzato, quindi convertiamolo in un test automatico.</p>\n<p>Il posto che per convenzione ospita i test di una applicazione è il file <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code>; il sistema di testing troverà automaticamente i test in ogni file il cui nome inizia per <code class=\"docutils literal notranslate\"><span class=\"pre\">test</span></code>.</p>\n<p>Metti quanto segue nel file <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code> nell’applicazione <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/tests.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">import</span><span class=\"w\"> </span><span class=\"nn\">datetime</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.test</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">TestCase</span>\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.utils</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">timezone</span>\n\n<span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">.models</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Question</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">QuestionModelTests</span><span class=\"p\">(</span><span class=\"n\">TestCase</span><span class=\"p\">):</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_was_published_recently_with_future_question</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        was_published_recently() returns False for questions whose pub_date</span>\n<span class=\"sd\">        is in the future.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">time</span> <span class=\"o\">=</span> <span class=\"n\">timezone</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span> <span class=\"o\">+</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">timedelta</span><span class=\"p\">(</span><span class=\"n\">days</span><span class=\"o\">=</span><span class=\"mi\">30</span><span class=\"p\">)</span>\n        <span class=\"n\">future_question</span> <span class=\"o\">=</span> <span class=\"n\">Question</span><span class=\"p\">(</span><span class=\"n\">pub_date</span><span class=\"o\">=</span><span class=\"n\">time</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertIs</span><span class=\"p\">(</span><span class=\"n\">future_question</span><span class=\"o\">.</span><span class=\"n\">was_published_recently</span><span class=\"p\">(),</span> <span class=\"kc\">False</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>Qui abbiamo creato una sottoclasse <a class=\"reference internal\" href=\"/it/4.1/topics/testing/tools/#django.test.TestCase\" title=\"django.test.TestCase\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">django.test.TestCase</span></code></a> con un metodo che crea una istanza di <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> con una <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> nel futuro. Quindi controlliamo l’output di <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently()</span></code> - che <em>dovrebbe</em> essere False.</p>\n</section>\n<section id=\"running-tests\">\n<h3>Eseguire i test<a class=\"heading-anchor\" href=\"#running-tests\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Nel terminale, possiamo eseguire il nostro test:</p>\n<div class=\"console\" data-console><div class=\"console-panel\" data-platform=\"unix\"><p class=\"console-label\" id=\"console-1-unix-label\">Linux / macOS</p><div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Shell code\"><code><span class=\"gp\">$ </span>python<span class=\"w\"> </span>manage.py<span class=\"w\"> </span><span class=\"nb\">test</span><span class=\"w\"> </span>polls\n</code></pre></div>\n</div><div class=\"console-panel\" data-platform=\"windows\"><p class=\"console-label\" id=\"console-1-windows-label\">Windows</p><div class=\"code-block\" data-language=\"doscon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Windows</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Windows shell\"><code><span class=\"gp\">...\\&gt;</span> py manage.py test polls\n</code></pre></div></div></div>\n<p>e vedrai qualcosa del genere:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">Creating</span> <span class=\"n\">test</span> <span class=\"n\">database</span> <span class=\"k\">for</span> <span class=\"n\">alias</span> <span class=\"s1\">&#39;default&#39;</span><span class=\"o\">...</span>\n<span class=\"n\">System</span> <span class=\"n\">check</span> <span class=\"n\">identified</span> <span class=\"n\">no</span> <span class=\"n\">issues</span> <span class=\"p\">(</span><span class=\"mi\">0</span> <span class=\"n\">silenced</span><span class=\"p\">)</span><span class=\"o\">.</span>\n<span class=\"n\">F</span>\n<span class=\"o\">======================================================================</span>\n<span class=\"n\">FAIL</span><span class=\"p\">:</span> <span class=\"n\">test_was_published_recently_with_future_question</span> <span class=\"p\">(</span><span class=\"n\">polls</span><span class=\"o\">.</span><span class=\"n\">tests</span><span class=\"o\">.</span><span class=\"n\">QuestionModelTests</span><span class=\"p\">)</span>\n<span class=\"o\">----------------------------------------------------------------------</span>\n<span class=\"n\">Traceback</span> <span class=\"p\">(</span><span class=\"n\">most</span> <span class=\"n\">recent</span> <span class=\"n\">call</span> <span class=\"n\">last</span><span class=\"p\">):</span>\n  <span class=\"n\">File</span> <span class=\"s2\">&quot;/path/to/mysite/polls/tests.py&quot;</span><span class=\"p\">,</span> <span class=\"n\">line</span> <span class=\"mi\">16</span><span class=\"p\">,</span> <span class=\"ow\">in</span> <span class=\"n\">test_was_published_recently_with_future_question</span>\n    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertIs</span><span class=\"p\">(</span><span class=\"n\">future_question</span><span class=\"o\">.</span><span class=\"n\">was_published_recently</span><span class=\"p\">(),</span> <span class=\"kc\">False</span><span class=\"p\">)</span>\n<span class=\"ne\">AssertionError</span><span class=\"p\">:</span> <span class=\"kc\">True</span> <span class=\"ow\">is</span> <span class=\"ow\">not</span> <span class=\"kc\">False</span>\n\n<span class=\"o\">----------------------------------------------------------------------</span>\n<span class=\"n\">Ran</span> <span class=\"mi\">1</span> <span class=\"n\">test</span> <span class=\"ow\">in</span> <span class=\"mf\">0.001</span><span class=\"n\">s</span>\n\n<span class=\"n\">FAILED</span> <span class=\"p\">(</span><span class=\"n\">failures</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n<span class=\"n\">Destroying</span> <span class=\"n\">test</span> <span class=\"n\">database</span> <span class=\"k\">for</span> <span class=\"n\">alias</span> <span class=\"s1\">&#39;default&#39;</span><span class=\"o\">...</span>\n</code></pre></div>\n<aside class=\"admonition-different-error admonition\">\n<p class=\"admonition-title\">Errore diverso?</p>\n<p>Se al contrario ottieni un <code class=\"docutils literal notranslate\"><span class=\"pre\">NameError</span></code>, potresti esserti perso uno step nella <a class=\"reference internal\" href=\"/it/4.1/intro/tutorial02/#tutorial02-import-timezone\"><span class=\"std std-ref\">Parte 2</span></a> dove abbiamo aggiunto gli import di <code class=\"docutils literal notranslate\"><span class=\"pre\">datetime</span></code> e <code class=\"docutils literal notranslate\"><span class=\"pre\">timezone</span></code> a <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/models.py</span></code>. Copia gli import da quella sezione e prova a lanciare di nuovo i test.</p>\n</aside>\n<p>Quello che è successo è questo</p>\n<ul class=\"simple\">\n<li><p><code class=\"docutils literal notranslate\"><span class=\"pre\">manage.py</span> <span class=\"pre\">test</span> <span class=\"pre\">polls</span></code> cerca i test nell’applicazione <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code></p></li>\n<li><p>ha trovato una sottoclasse di tipo  <a class=\"reference internal\" href=\"/it/4.1/topics/testing/tools/#django.test.TestCase\" title=\"django.test.TestCase\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">django.test.TestCase</span></code></a></p></li>\n<li><p>ha creato un database speciale con lo scopo di testing</p></li>\n<li><p>cerca metodi di test - quelli i cui nomi iniziano con <code class=\"docutils literal notranslate\"><span class=\"pre\">test</span></code></p></li>\n<li><p>in <code class=\"docutils literal notranslate\"><span class=\"pre\">test_was_published_recently_with_future_question</span></code> ha creato una istanza di <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> il cui campo <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> è avanti di 30 giorni nel futuro</p></li>\n<li><p>…ed usando il metodo <code class=\"docutils literal notranslate\"><span class=\"pre\">assertIs()</span></code>, ha scoperto che il suo <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently()</span></code> restituisce <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>, anche se volevamo che restituisse <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code></p></li>\n</ul>\n<p>Il test ci informa su quale test è fallito e ci dice anche la linea su cui si è verificato il fallimento.</p>\n</section>\n<section id=\"fixing-the-bug\">\n<h3>Correggere il bug<a class=\"heading-anchor\" href=\"#fixing-the-bug\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Sappiamo già che il problema è: <code class=\"docutils literal notranslate\"><span class=\"pre\">Question.was_published_recently()</span></code> dovrebbe restituire <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code> se la sua <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> è futura. Correggi il metodo in <code class=\"docutils literal notranslate\"><span class=\"pre\">models.py</span></code>, così che restiuisca <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> solo se la data è nel passato:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/models.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">was_published_recently</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n    <span class=\"n\">now</span> <span class=\"o\">=</span> <span class=\"n\">timezone</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span>\n    <span class=\"k\">return</span> <span class=\"n\">now</span> <span class=\"o\">-</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">timedelta</span><span class=\"p\">(</span><span class=\"n\">days</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span> <span class=\"o\">&lt;=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">pub_date</span> <span class=\"o\">&lt;=</span> <span class=\"n\">now</span>\n</code></pre></figure>\n<p>ed eseguire nuovamente il test</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"n\">Creating</span> <span class=\"n\">test</span> <span class=\"n\">database</span> <span class=\"k\">for</span> <span class=\"n\">alias</span> <span class=\"s1\">&#39;default&#39;</span><span class=\"o\">...</span>\n<span class=\"n\">System</span> <span class=\"n\">check</span> <span class=\"n\">identified</span> <span class=\"n\">no</span> <span class=\"n\">issues</span> <span class=\"p\">(</span><span class=\"mi\">0</span> <span class=\"n\">silenced</span><span class=\"p\">)</span><span class=\"o\">.</span>\n<span class=\"o\">.</span>\n<span class=\"o\">----------------------------------------------------------------------</span>\n<span class=\"n\">Ran</span> <span class=\"mi\">1</span> <span class=\"n\">test</span> <span class=\"ow\">in</span> <span class=\"mf\">0.001</span><span class=\"n\">s</span>\n\n<span class=\"n\">OK</span>\n<span class=\"n\">Destroying</span> <span class=\"n\">test</span> <span class=\"n\">database</span> <span class=\"k\">for</span> <span class=\"n\">alias</span> <span class=\"s1\">&#39;default&#39;</span><span class=\"o\">...</span>\n</code></pre></div>\n<p>Dopo aver identificato un bug, abbiamo scritto un test che lo evidenzia e corretto il bug nel codice in modo che il nostro test venga superato.</p>\n<p>Molte altre cose potrebbero andare storte con la nostra applicazione in futuro, ma possiamo essere sicuri che non reintrodurremo inavvertitamente questo specifico bug perché l’esecuzione del test ci avviserà immediatamente. Possiamo considerare questa piccola parte dell’applicazione bloccata in modo sicuro per sempre.</p>\n</section>\n<section id=\"more-comprehensive-tests\">\n<h3>Test più completi<a class=\"heading-anchor\" href=\"#more-comprehensive-tests\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Già che ci siamo, possiamo aggiustare meglio il metodo <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently()</span></code>; in effetti, potrebbe essere estremamente imbarazzante se nel tentativo di correggere un bug ne introducessimo un altro.</p>\n<p>Aggiungi altri due metodi di test alla stessa classe, per testare il comportamento del metodo in modo più esteso:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/tests.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_was_published_recently_with_old_question</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    was_published_recently() returns False for questions whose pub_date</span>\n<span class=\"sd\">    is older than 1 day.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">time</span> <span class=\"o\">=</span> <span class=\"n\">timezone</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">timedelta</span><span class=\"p\">(</span><span class=\"n\">days</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">,</span> <span class=\"n\">seconds</span><span class=\"o\">=</span><span class=\"mi\">1</span><span class=\"p\">)</span>\n    <span class=\"n\">old_question</span> <span class=\"o\">=</span> <span class=\"n\">Question</span><span class=\"p\">(</span><span class=\"n\">pub_date</span><span class=\"o\">=</span><span class=\"n\">time</span><span class=\"p\">)</span>\n    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertIs</span><span class=\"p\">(</span><span class=\"n\">old_question</span><span class=\"o\">.</span><span class=\"n\">was_published_recently</span><span class=\"p\">(),</span> <span class=\"kc\">False</span><span class=\"p\">)</span>\n\n<span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_was_published_recently_with_recent_question</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    was_published_recently() returns True for questions whose pub_date</span>\n<span class=\"sd\">    is within the last day.</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">time</span> <span class=\"o\">=</span> <span class=\"n\">timezone</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span> <span class=\"o\">-</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">timedelta</span><span class=\"p\">(</span><span class=\"n\">hours</span><span class=\"o\">=</span><span class=\"mi\">23</span><span class=\"p\">,</span> <span class=\"n\">minutes</span><span class=\"o\">=</span><span class=\"mi\">59</span><span class=\"p\">,</span> <span class=\"n\">seconds</span><span class=\"o\">=</span><span class=\"mi\">59</span><span class=\"p\">)</span>\n    <span class=\"n\">recent_question</span> <span class=\"o\">=</span> <span class=\"n\">Question</span><span class=\"p\">(</span><span class=\"n\">pub_date</span><span class=\"o\">=</span><span class=\"n\">time</span><span class=\"p\">)</span>\n    <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertIs</span><span class=\"p\">(</span><span class=\"n\">recent_question</span><span class=\"o\">.</span><span class=\"n\">was_published_recently</span><span class=\"p\">(),</span> <span class=\"kc\">True</span><span class=\"p\">)</span>\n</code></pre></figure>\n<p>Ed adesso abbiamo tre test che confermano che <code class=\"docutils literal notranslate\"><span class=\"pre\">Question.was_published_recently()</span></code> restuisce valori ragionevoli per le domande passate, recenti e future.</p>\n<p>Di nuovo, <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code> è una applicazione minimale ma a prescindere da quanto cresca in complessità o con quale codice interagisca, adesso abbiamo qualche garanzia che i metodi per cui abbiamo scritto test si comporteranno come ci aspettiamo.</p>\n</section>\n</section>\n<section id=\"test-a-view\">\n<h2>Testare una vista<a class=\"heading-anchor\" href=\"#test-a-view\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>L’applicazione dei sondaggi agisce in modo abbastanza indiscriminato: pubblicherà ogni domanda, incluse quelle il cui campo <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> è futuro. Dovremmo migliorare questa cosa. Impostare una <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> nel futuro significa che la domanda deve essere pubblicata in quel momento ma fino ad allora deve essere invisibile.</p>\n<section id=\"a-test-for-a-view\">\n<h3>Un test per una vista<a class=\"heading-anchor\" href=\"#a-test-for-a-view\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Quando abbiamo corretto il bug sopra, abbiamo scritto prima il test e poi il codice per risolverlo. In effetti è stato un esempio di sviluppo basato sui test (TDD), ma non importa in quale ordine svolgiamo il lavoro.</p>\n<p>Nel nostro primo test, ci siamo concentrati sul comportamento interno del codice. Per questo test, vogliamo verificarne il comportamento come se fosse fatto da un utente tramite un browser web.</p>\n<p>Prima di provare a riparare qualcosa, diamo un’occhiata agli strumenti a nostra disposizione.</p>\n</section>\n<section id=\"the-django-test-client\">\n<h3>Il client test di Django<a class=\"heading-anchor\" href=\"#the-django-test-client\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Django offre una <a class=\"reference internal\" href=\"/it/4.1/topics/testing/tools/#django.test.Client\" title=\"django.test.Client\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">Client</span></code></a> di test per simulare un utente che interagisce con il codice a livello della view. Possiamo usarla in  <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code> o persino nella <a class=\"reference internal\" href=\"/it/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a>.</p>\n<p>Cominciamo di nuovo con la <a class=\"reference internal\" href=\"/it/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a>, dove dobbiamo fare un paio di cose che non saranno necessarie in <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code>. La prima è approntare l’ambiente di test nella <a class=\"reference internal\" href=\"/it/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a>:</p>\n<div class=\"console\" data-console><div class=\"console-panel\" data-platform=\"unix\"><p class=\"console-label\" id=\"console-2-unix-label\">Linux / macOS</p><div class=\"code-block\" data-language=\"console\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Shell</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Shell code\"><code><span class=\"gp\">$ </span>python<span class=\"w\"> </span>manage.py<span class=\"w\"> </span>shell\n</code></pre></div>\n</div><div class=\"console-panel\" data-platform=\"windows\"><p class=\"console-label\" id=\"console-2-windows-label\">Windows</p><div class=\"code-block\" data-language=\"doscon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Windows</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Windows shell\"><code><span class=\"gp\">...\\&gt;</span> py manage.py shell\n</code></pre></div></div></div>\n<div class=\"code-block\" data-language=\"pycon\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python console</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python console code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.test.utils</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">setup_test_environment</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">setup_test_environment</span><span class=\"p\">()</span>\n</code></pre></div>\n<p><a class=\"reference internal\" href=\"/it/4.1/topics/testing/advanced/#django.test.utils.setup_test_environment\" title=\"django.test.utils.setup_test_environment\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">setup_test_environment()</span></code></a> installa un renderer di template che ci permette di esaminare alcuni attributi in più sulle responses, come <code class=\"docutils literal notranslate\"><span class=\"pre\">response.context</span></code> che altrimenti non sarebbe disponibile. Nota che questo metodo <em>non</em> inizializza un database di test, ciò che segue quindi sarà lanciato sul database esistente e l’output può differire leggermente, dipendentemente dalle domande che hai già creato. Puoi ottenere risultati inaspettati se la tua <code class=\"docutils literal notranslate\"><span class=\"pre\">TIME_ZONE</span></code> in <code class=\"docutils literal notranslate\"><span class=\"pre\">settings.py</span></code> non è corretta. Se non ti sei ricordato di impostarla prima, controllala prima di continuare.</p>\n<p>Poi abbiamo bisogno di importare la classe client per il test (più tardi in <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code> useremo la classe <a class=\"reference internal\" href=\"/it/4.1/topics/testing/tools/#django.test.TestCase\" title=\"django.test.TestCase\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">django.test.TestCase</span></code></a>, che arriva con il suo client, così che questo non sarà necessario):</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.test</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">Client</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># create an instance of the client for our use</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">client</span> <span class=\"o\">=</span> <span class=\"n\">Client</span><span class=\"p\">()</span>\n</code></pre></div>\n<p>Preparato ciò, possiamo chiedere al client di fare del lavoro per noi:</p>\n<div class=\"code-block\" data-language=\"default\"><div class=\"code-block-toolbar\"><span class=\"code-block-language\">Code</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Code code\"><code><span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># get a response from &#39;/&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"s1\">&#39;/&#39;</span><span class=\"p\">)</span>\n<span class=\"go\">Not Found: /</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># we should expect a 404 from that address; if you instead see an</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># &quot;Invalid HTTP_HOST header&quot; error and a 400 response, you probably</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># omitted the setup_test_environment() call described earlier.</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">status_code</span>\n<span class=\"go\">404</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># on the other hand we should expect to find something at &#39;/polls/&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"c1\"># we&#39;ll use &#39;reverse()&#39; rather than a hardcoded URL</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">reverse</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls:index&#39;</span><span class=\"p\">))</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">status_code</span>\n<span class=\"go\">200</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">content</span>\n<span class=\"go\">b&#39;\\n    &lt;ul&gt;\\n    \\n        &lt;li&gt;&lt;a href=&quot;/polls/1/&quot;&gt;What&amp;#x27;s up?&lt;/a&gt;&lt;/li&gt;\\n    \\n    &lt;/ul&gt;\\n\\n&#39;</span>\n<span class=\"gp\">&gt;&gt;&gt; </span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">context</span><span class=\"p\">[</span><span class=\"s1\">&#39;latest_question_list&#39;</span><span class=\"p\">]</span>\n<span class=\"go\">&lt;QuerySet [&lt;Question: What&#39;s up?&gt;]&gt;</span>\n</code></pre></div>\n</section>\n<section id=\"improving-our-view\">\n<h3>Migliorare la nostra vista<a class=\"heading-anchor\" href=\"#improving-our-view\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>La lista di questionari mostra i questionari che non sono ancora stati pubblicati (cioè quelli la cui <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> è futura). Mettiamo a posto questa cosa.</p>\n<p>Nel <a class=\"reference internal\" href=\"/it/4.1/intro/tutorial04/\"><span class=\"doc\">Tutorial 4</span></a> abbiamo introdotto una view basate su classe, basata su <a class=\"reference internal\" href=\"/it/4.1/ref/class-based-views/generic-display/#django.views.generic.list.ListView\" title=\"django.views.generic.list.ListView\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">ListView</span></code></a>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">IndexView</span><span class=\"p\">(</span><span class=\"n\">generic</span><span class=\"o\">.</span><span class=\"n\">ListView</span><span class=\"p\">):</span>\n    <span class=\"n\">template_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;polls/index.html&#39;</span>\n    <span class=\"n\">context_object_name</span> <span class=\"o\">=</span> <span class=\"s1\">&#39;latest_question_list&#39;</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_queryset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;Return the last five published questions.&quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">Question</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">order_by</span><span class=\"p\">(</span><span class=\"s1\">&#39;-pub_date&#39;</span><span class=\"p\">)[:</span><span class=\"mi\">5</span><span class=\"p\">]</span>\n</code></pre></figure>\n<p>Dobbiamo modificare il metodo <code class=\"docutils literal notranslate\"><span class=\"pre\">get_queryset()</span></code> e cambiarlo in modo che controlli anche la data confrontandola con <code class=\"docutils literal notranslate\"><span class=\"pre\">timezone.now()</span></code>. Per prima cosa dobbiamo aggiungere un import:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.utils</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">timezone</span>\n</code></pre></figure>\n<p>e poi dobbiamo correggere il metodo <code class=\"docutils literal notranslate\"><span class=\"pre\">get_queryset</span></code> in questo modo:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_queryset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Return the last five published questions (not including those set to be</span>\n<span class=\"sd\">    published in the future).</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"k\">return</span> <span class=\"n\">Question</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span>\n        <span class=\"n\">pub_date__lte</span><span class=\"o\">=</span><span class=\"n\">timezone</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span>\n    <span class=\"p\">)</span><span class=\"o\">.</span><span class=\"n\">order_by</span><span class=\"p\">(</span><span class=\"s1\">&#39;-pub_date&#39;</span><span class=\"p\">)[:</span><span class=\"mi\">5</span><span class=\"p\">]</span>\n</code></pre></figure>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">Question.objects.filter(pub_date__lte=timezone.now())</span></code> restituisce un queryset contenente le <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> la cui <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> è minore o uguale a - cioè prima o allo stesso momento di - <code class=\"docutils literal notranslate\"><span class=\"pre\">timezone.now</span></code>.</p>\n</section>\n<section id=\"testing-our-new-view\">\n<h3>Testare la nostra nuova vista<a class=\"heading-anchor\" href=\"#testing-our-new-view\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Adesso puoi renderti orgoglioso del fatto che questo si comporti come ci si aspetta lanciando <code class=\"docutils literal notranslate\"><span class=\"pre\">runserver</span></code>, caricando il sito nel browser, creando <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> le cui date sono passate e future e controllando che solo quelle pubblicate appaiano nella lista. Non lo vuoi fare <em>tutte le volte che cambi qualcosa che potrebbe aver ripercussioni su questo</em> -  quindi creiamo anche un test, basato sulla nostra sessione <a class=\"reference internal\" href=\"/it/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> di prima.</p>\n<p>Aggiungere quanto segue a <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/tests.py</span></code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/tests.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"kn\">from</span><span class=\"w\"> </span><span class=\"nn\">django.urls</span><span class=\"w\"> </span><span class=\"kn\">import</span> <span class=\"n\">reverse</span>\n</code></pre></figure>\n<p>e creeremo una funzione scorciatoia per creare domande così come una nuiova classe di test:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/tests.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">create_question</span><span class=\"p\">(</span><span class=\"n\">question_text</span><span class=\"p\">,</span> <span class=\"n\">days</span><span class=\"p\">):</span>\n<span class=\"w\">    </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">    Create a question with the given `question_text` and published the</span>\n<span class=\"sd\">    given number of `days` offset to now (negative for questions published</span>\n<span class=\"sd\">    in the past, positive for questions that have yet to be published).</span>\n<span class=\"sd\">    &quot;&quot;&quot;</span>\n    <span class=\"n\">time</span> <span class=\"o\">=</span> <span class=\"n\">timezone</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">()</span> <span class=\"o\">+</span> <span class=\"n\">datetime</span><span class=\"o\">.</span><span class=\"n\">timedelta</span><span class=\"p\">(</span><span class=\"n\">days</span><span class=\"o\">=</span><span class=\"n\">days</span><span class=\"p\">)</span>\n    <span class=\"k\">return</span> <span class=\"n\">Question</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">create</span><span class=\"p\">(</span><span class=\"n\">question_text</span><span class=\"o\">=</span><span class=\"n\">question_text</span><span class=\"p\">,</span> <span class=\"n\">pub_date</span><span class=\"o\">=</span><span class=\"n\">time</span><span class=\"p\">)</span>\n\n\n<span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">QuestionIndexViewTests</span><span class=\"p\">(</span><span class=\"n\">TestCase</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_no_questions</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        If no questions exist, an appropriate message is displayed.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls:index&#39;</span><span class=\"p\">))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertEqual</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">status_code</span><span class=\"p\">,</span> <span class=\"mi\">200</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertContains</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"s2\">&quot;No polls are available.&quot;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertQuerysetEqual</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">context</span><span class=\"p\">[</span><span class=\"s1\">&#39;latest_question_list&#39;</span><span class=\"p\">],</span> <span class=\"p\">[])</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_past_question</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Questions with a pub_date in the past are displayed on the</span>\n<span class=\"sd\">        index page.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">question</span> <span class=\"o\">=</span> <span class=\"n\">create_question</span><span class=\"p\">(</span><span class=\"n\">question_text</span><span class=\"o\">=</span><span class=\"s2\">&quot;Past question.&quot;</span><span class=\"p\">,</span> <span class=\"n\">days</span><span class=\"o\">=-</span><span class=\"mi\">30</span><span class=\"p\">)</span>\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls:index&#39;</span><span class=\"p\">))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertQuerysetEqual</span><span class=\"p\">(</span>\n            <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">context</span><span class=\"p\">[</span><span class=\"s1\">&#39;latest_question_list&#39;</span><span class=\"p\">],</span>\n            <span class=\"p\">[</span><span class=\"n\">question</span><span class=\"p\">],</span>\n        <span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_future_question</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Questions with a pub_date in the future aren&#39;t displayed on</span>\n<span class=\"sd\">        the index page.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">create_question</span><span class=\"p\">(</span><span class=\"n\">question_text</span><span class=\"o\">=</span><span class=\"s2\">&quot;Future question.&quot;</span><span class=\"p\">,</span> <span class=\"n\">days</span><span class=\"o\">=</span><span class=\"mi\">30</span><span class=\"p\">)</span>\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls:index&#39;</span><span class=\"p\">))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertContains</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"s2\">&quot;No polls are available.&quot;</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertQuerysetEqual</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">context</span><span class=\"p\">[</span><span class=\"s1\">&#39;latest_question_list&#39;</span><span class=\"p\">],</span> <span class=\"p\">[])</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_future_question_and_past_question</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Even if both past and future questions exist, only past questions</span>\n<span class=\"sd\">        are displayed.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">question</span> <span class=\"o\">=</span> <span class=\"n\">create_question</span><span class=\"p\">(</span><span class=\"n\">question_text</span><span class=\"o\">=</span><span class=\"s2\">&quot;Past question.&quot;</span><span class=\"p\">,</span> <span class=\"n\">days</span><span class=\"o\">=-</span><span class=\"mi\">30</span><span class=\"p\">)</span>\n        <span class=\"n\">create_question</span><span class=\"p\">(</span><span class=\"n\">question_text</span><span class=\"o\">=</span><span class=\"s2\">&quot;Future question.&quot;</span><span class=\"p\">,</span> <span class=\"n\">days</span><span class=\"o\">=</span><span class=\"mi\">30</span><span class=\"p\">)</span>\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls:index&#39;</span><span class=\"p\">))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertQuerysetEqual</span><span class=\"p\">(</span>\n            <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">context</span><span class=\"p\">[</span><span class=\"s1\">&#39;latest_question_list&#39;</span><span class=\"p\">],</span>\n            <span class=\"p\">[</span><span class=\"n\">question</span><span class=\"p\">],</span>\n        <span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_two_past_questions</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        The questions index page may display multiple questions.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">question1</span> <span class=\"o\">=</span> <span class=\"n\">create_question</span><span class=\"p\">(</span><span class=\"n\">question_text</span><span class=\"o\">=</span><span class=\"s2\">&quot;Past question 1.&quot;</span><span class=\"p\">,</span> <span class=\"n\">days</span><span class=\"o\">=-</span><span class=\"mi\">30</span><span class=\"p\">)</span>\n        <span class=\"n\">question2</span> <span class=\"o\">=</span> <span class=\"n\">create_question</span><span class=\"p\">(</span><span class=\"n\">question_text</span><span class=\"o\">=</span><span class=\"s2\">&quot;Past question 2.&quot;</span><span class=\"p\">,</span> <span class=\"n\">days</span><span class=\"o\">=-</span><span class=\"mi\">5</span><span class=\"p\">)</span>\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls:index&#39;</span><span class=\"p\">))</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertQuerysetEqual</span><span class=\"p\">(</span>\n            <span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">context</span><span class=\"p\">[</span><span class=\"s1\">&#39;latest_question_list&#39;</span><span class=\"p\">],</span>\n            <span class=\"p\">[</span><span class=\"n\">question2</span><span class=\"p\">,</span> <span class=\"n\">question1</span><span class=\"p\">],</span>\n        <span class=\"p\">)</span>\n</code></pre></figure>\n<p>Diamo un occhiata da vicino.</p>\n<p>La prima è una funzione scorciatoia, <code class=\"docutils literal notranslate\"><span class=\"pre\">create_question</span></code>, che astrae alcune ripetizioni nel processo di creazione delle domande.</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">test_no_questions</span></code> non crea domande, ma controlla il messaggio: «Non ci sono sondaggi disponibili.» e verifica che <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code> sia vuota. Nota che la classe <a class=\"reference internal\" href=\"/it/4.1/topics/testing/tools/#django.test.TestCase\" title=\"django.test.TestCase\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">django.test.TestCase</span></code></a> offre alcuni metodi di asserzioni aggiuntivi. In questi esempi, usiamo <a class=\"reference internal\" href=\"/it/4.1/topics/testing/tools/#django.test.SimpleTestCase.assertContains\" title=\"django.test.SimpleTestCase.assertContains\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">assertContains()</span></code></a> e <a class=\"reference internal\" href=\"/it/4.1/topics/testing/tools/#django.test.TransactionTestCase.assertQuerysetEqual\" title=\"django.test.TransactionTestCase.assertQuerysetEqual\"><code class=\"xref py py-meth docutils literal notranslate\"><span class=\"pre\">assertQuerysetEqual()</span></code></a>.</p>\n<p>In <code class=\"docutils literal notranslate\"><span class=\"pre\">test_past_question</span></code>, creiamo una domanda e verifichiamo che appaia nell’elenco.</p>\n<p>In <code class=\"docutils literal notranslate\"><span class=\"pre\">test_future_question</span></code>, creiamo una domanda con una <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> nel futuro. Il database viene reimpostato per ogni metodo di test, quindi la prima domanda non c’è più e così, di nuovo, l’indice non dovrebbe mostrare nessuna domanda.</p>\n<p>E così via. In effetti, stiamo usando i test per raccontare la storia dell’input dell’admin e la user experience sul sito, controllando ad ogni stato e per ogni cambiamento del sito, che i cambiamenti vengano pubblicati.</p>\n</section>\n<section id=\"testing-the-detailview\">\n<h3>Testare la <code class=\"docutils literal notranslate\"><span class=\"pre\">DetailView</span></code><a class=\"heading-anchor\" href=\"#testing-the-detailview\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Quel che abbiamo funziona bene; eppure, anche se le domande future non appaiono nell”<em>indice</em>, gli utenti possono ancora raggiungere se conoscono o indovinano la URL giusta. Quindi dobbiamo aggiungere una restrizione simile a <code class=\"docutils literal notranslate\"><span class=\"pre\">DetailView</span></code>:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/views.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">DetailView</span><span class=\"p\">(</span><span class=\"n\">generic</span><span class=\"o\">.</span><span class=\"n\">DetailView</span><span class=\"p\">):</span>\n    <span class=\"o\">...</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">get_queryset</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        Excludes any questions that aren&#39;t published yet.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"k\">return</span> <span class=\"n\">Question</span><span class=\"o\">.</span><span class=\"n\">objects</span><span class=\"o\">.</span><span class=\"n\">filter</span><span class=\"p\">(</span><span class=\"n\">pub_date__lte</span><span class=\"o\">=</span><span class=\"n\">timezone</span><span class=\"o\">.</span><span class=\"n\">now</span><span class=\"p\">())</span>\n</code></pre></figure>\n<p>Dovremmo quindi aggiungere alcuni test, per verificare che una <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code>  la cui <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> sia nel passato, possa essere visualizzata e quella con <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> nel futuro non lo sia:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\"><code class=\"docutils literal notranslate\"><span class=\"pre\">polls/tests.py</span></code></figcaption>\n<div class=\"code-block-toolbar\"><span class=\"code-block-language\">Python</span><button type=\"button\" class=\"copy-button\" data-copy hidden><span class=\"copy-button-label\">Copy</span></button></div><pre role=\"group\" tabindex=\"0\" aria-label=\"Python code\"><code><span class=\"k\">class</span><span class=\"w\"> </span><span class=\"nc\">QuestionDetailViewTests</span><span class=\"p\">(</span><span class=\"n\">TestCase</span><span class=\"p\">):</span>\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_future_question</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        The detail view of a question with a pub_date in the future</span>\n<span class=\"sd\">        returns a 404 not found.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">future_question</span> <span class=\"o\">=</span> <span class=\"n\">create_question</span><span class=\"p\">(</span><span class=\"n\">question_text</span><span class=\"o\">=</span><span class=\"s1\">&#39;Future question.&#39;</span><span class=\"p\">,</span> <span class=\"n\">days</span><span class=\"o\">=</span><span class=\"mi\">5</span><span class=\"p\">)</span>\n        <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls:detail&#39;</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">future_question</span><span class=\"o\">.</span><span class=\"n\">id</span><span class=\"p\">,))</span>\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertEqual</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"o\">.</span><span class=\"n\">status_code</span><span class=\"p\">,</span> <span class=\"mi\">404</span><span class=\"p\">)</span>\n\n    <span class=\"k\">def</span><span class=\"w\"> </span><span class=\"nf\">test_past_question</span><span class=\"p\">(</span><span class=\"bp\">self</span><span class=\"p\">):</span>\n<span class=\"w\">        </span><span class=\"sd\">&quot;&quot;&quot;</span>\n<span class=\"sd\">        The detail view of a question with a pub_date in the past</span>\n<span class=\"sd\">        displays the question&#39;s text.</span>\n<span class=\"sd\">        &quot;&quot;&quot;</span>\n        <span class=\"n\">past_question</span> <span class=\"o\">=</span> <span class=\"n\">create_question</span><span class=\"p\">(</span><span class=\"n\">question_text</span><span class=\"o\">=</span><span class=\"s1\">&#39;Past Question.&#39;</span><span class=\"p\">,</span> <span class=\"n\">days</span><span class=\"o\">=-</span><span class=\"mi\">5</span><span class=\"p\">)</span>\n        <span class=\"n\">url</span> <span class=\"o\">=</span> <span class=\"n\">reverse</span><span class=\"p\">(</span><span class=\"s1\">&#39;polls:detail&#39;</span><span class=\"p\">,</span> <span class=\"n\">args</span><span class=\"o\">=</span><span class=\"p\">(</span><span class=\"n\">past_question</span><span class=\"o\">.</span><span class=\"n\">id</span><span class=\"p\">,))</span>\n        <span class=\"n\">response</span> <span class=\"o\">=</span> <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">client</span><span class=\"o\">.</span><span class=\"n\">get</span><span class=\"p\">(</span><span class=\"n\">url</span><span class=\"p\">)</span>\n        <span class=\"bp\">self</span><span class=\"o\">.</span><span class=\"n\">assertContains</span><span class=\"p\">(</span><span class=\"n\">response</span><span class=\"p\">,</span> <span class=\"n\">past_question</span><span class=\"o\">.</span><span class=\"n\">question_text</span><span class=\"p\">)</span>\n</code></pre></figure>\n</section>\n<section id=\"ideas-for-more-tests\">\n<h3>Idee per altri test<a class=\"heading-anchor\" href=\"#ideas-for-more-tests\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h3>\n<p>Dovremmo aggiungere un metodo simile a <code class=\"docutils literal notranslate\"><span class=\"pre\">get_queryset</span></code> a <code class=\"docutils literal notranslate\"><span class=\"pre\">ResultsView</span></code> e creare una nuova classe di test per quella view. Sarà molto simile a quello che abbiamo appena creato; in effetti ci saranno un sacco di ripetizioni.</p>\n<p>Noi potremmo migliorare la nostra applicazione in altri modi, aggiungendo test. Per esempio, è sciocco che <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> possa essere pubblicato sul sito ma non ha  <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code>. Le nostre view potrebbero controllare questo scenario, ed escludere questo tipo di <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code>. I nostri test potrebbero creare una <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> senza <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code> e quindi testare che non sia pubblicata, così come potremmo creare una <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> simile, ma <em>con</em>  <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code> e testare che <em>venga</em> pubblicata</p>\n<p>Probabilmente gli utenti amministratori loggati dovrebbero poter vedere le <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> non pubblicate, ma non gli utenti normali. Sottolineamo: qualsiasi cosa venga aggiunta al codice per ottenere questo scopo, dovrebbe essere coperto da un test, sia che tu scriva prima il test e poi il codice per superare il test, sia che lavori sulla logica del codice e poi scrivi un test che la copra.</p>\n<p>Ad un certo punto sarai obbligato a guardare i tuoi test e chiederti se il tuo codice soffra di eccesso di test , il che ci porta a:</p>\n</section>\n</section>\n<section id=\"when-testing-more-is-better\">\n<h2>Nei test, di più è meglio<a class=\"heading-anchor\" href=\"#when-testing-more-is-better\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Potrebbe sembrare che i nostri test aumentino senza controllo. A questa velocità ci sarà in breve tempo più codice nei nostri test che nella nostra applicazione, e la ripetizione è antiestetica, in comparazione con l’eleganza della brevità del resto del nostro codice.</p>\n<p>** Non importa <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">**</span></a>. Lascia che crescano. Per la maggior parte puoi scrivere un test una volta e poi dimenticartene. Continuerà a svolgere la sua funzione mentre continui a sviluppare il programma.</p>\n<p>A volte i test avranno bisogno di un aggiornamento. Mettiamo caso che cambiano le nostre view in modo che solo <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> con  <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code> vengano pubblicate. In questo caso, molti dei nostri test falliranno - <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">*</span></a>dicendoci esattamente quali test bisogna aggiornare, così che l’aggiornamento farà in modo da farli superare al prossimo giro.</p>\n<p>Al peggio, dal momento che continui a sviluppare, potrai trovarti ad avere alcuni test che ora sono ridondanti. Nonostante questo, non è un problema; testare la ridondanza è una <em>buona</em> prassi.</p>\n<p>Finché i tuoi test sono organizzati in modo ragionevole, non diventeranno ingestibili. Le buone regole pratiche includono avere:</p>\n<ul class=\"simple\">\n<li><p>Una <code class=\"docutils literal notranslate\"><span class=\"pre\">TestClass</span></code> separata per ogni model o view</p></li>\n<li><p>un metodo test separato per ogni set di condizioni che tu vuoi testare</p></li>\n<li><p>nomi di metodi di test che descrivono la loro funzione</p></li>\n</ul>\n</section>\n<section id=\"further-testing\">\n<h2>Altri test<a class=\"heading-anchor\" href=\"#further-testing\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Questo tutorial introduce solo alcune delle basi del testing. C’è molto di più che puoi fare ed una serie di strumenti molto utili sono a tua disposizione per realizzare cose molto ingegnose.</p>\n<p>Per esempio, mentre alcuni nostri test qui hanno coperto un po” di logica interna di un modello ed il modo in cui le view pubblicano le informazioni, puoi usare un framework «in-browser» come <a class=\"reference external\" href=\"https://www.selenium.dev/\">Selenium</a> per controllare il modo in cui il tuo HTML viene mostrato nel browser. Questi tool inoltre ti permettono di controllare non solo il comportamento del tuo codice Django ma anche, per esempio, del tuo JavaScript. E” veramente fantastico vedere come i test lanciano il browser e ci interagiscono, come se si trattasse di un essere umano! Django include <a class=\"reference internal\" href=\"/it/4.1/topics/testing/tools/#django.test.LiveServerTestCase\" title=\"django.test.LiveServerTestCase\"><code class=\"xref py py-class docutils literal notranslate\"><span class=\"pre\">LiveServerTestCase</span></code></a> per facilitare l’integrazione con tool come Selenium.</p>\n<p>Se hai un’applicazione complessa, potresti voler eseguire i test automaticamente ad ogni commit ai fini dell’integrazione <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Continuous_integration\">continua</a>, in modo che il controllo di qualità sia esso stesso, almeno parzialmente, automatizzato.</p>\n<p>Un buon modo per individuare parti della tua applicazione non testate è controllare la code coverage. Questo aiuta anche a identificare codice morto o fragile. Se tu non riesci a testare un pezzo di codice, di solito significa che quel codice dovrebbe essere rimosso o rielaborato. La Coverage aiuta a identificare codice non più in uso.  Vedi <a class=\"reference internal\" href=\"/it/4.1/topics/testing/advanced/#topics-testing-code-coverage\"><span class=\"std std-ref\">Integration with coverage.py</span></a> per avere dettagli.</p>\n<p><a class=\"reference internal\" href=\"/it/4.1/topics/testing/\"><span class=\"doc\">Testare in Django</span></a> contiene informazioni complete sui test.</p>\n</section>\n<section id=\"what-s-next\">\n<h2>Cos’altro?<a class=\"heading-anchor\" href=\"#what-s-next\"><span class=\"visually-hidden\">Link to this heading</span><span aria-hidden=\"true\">#</span></a></h2>\n<p>Per i dettagli completi sui test, vedi <a class=\"reference internal\" href=\"/it/4.1/topics/testing/\"><span class=\"doc\">Testare in Django</span></a>.</p>\n<p>Quando ti senti pronto e preparato nel testare le view Django, leggi <a class=\"reference internal\" href=\"/it/4.1/intro/tutorial06/\"><span class=\"doc\">parte 6 di questo tutorial</span></a>  per imparare a gestire i file statici.</p>\n</section>","rootId":"writing-your-first-django-app-part-5","toc":[{"title":"Introduzione ai test automatici","anchor":"introducing-automated-testing","children":[{"title":"Cosa sono i test automatici?","anchor":"what-are-automated-tests","children":[]},{"title":"Perché devi creare dei test","anchor":"why-you-need-to-create-tests","children":[{"title":"I test ti faranno risparmiare tempo","anchor":"tests-will-save-you-time","children":[]},{"title":"I test non si limitano a identificare i problemi, ma li prevengono","anchor":"tests-don-t-just-identify-problems-they-prevent-them","children":[]},{"title":"I test rendono il tuo codice più attraente","anchor":"tests-make-your-code-more-attractive","children":[]},{"title":"I test aiutano i gruppi a lavorare insieme","anchor":"tests-help-teams-work-together","children":[]}]}]},{"title":"Strategie basilari di test","anchor":"basic-testing-strategies","children":[]},{"title":"Scrivere il nostro primo test","anchor":"writing-our-first-test","children":[{"title":"Identifichiamo un bug","anchor":"we-identify-a-bug","children":[]},{"title":"Creare un test per esporre un bug","anchor":"create-a-test-to-expose-the-bug","children":[]},{"title":"Eseguire i test","anchor":"running-tests","children":[]},{"title":"Correggere il bug","anchor":"fixing-the-bug","children":[]},{"title":"Test più completi","anchor":"more-comprehensive-tests","children":[]}]},{"title":"Testare una vista","anchor":"test-a-view","children":[{"title":"Un test per una vista","anchor":"a-test-for-a-view","children":[]},{"title":"Il client test di Django","anchor":"the-django-test-client","children":[]},{"title":"Migliorare la nostra vista","anchor":"improving-our-view","children":[]},{"title":"Testare la nostra nuova vista","anchor":"testing-our-new-view","children":[]},{"title":"Testare la DetailView","anchor":"testing-the-detailview","children":[]},{"title":"Idee per altri test","anchor":"ideas-for-more-tests","children":[]}]},{"title":"Nei test, di più è meglio","anchor":"when-testing-more-is-better","children":[]},{"title":"Altri test","anchor":"further-testing","children":[]},{"title":"Cos’altro?","anchor":"what-s-next","children":[]}],"breadcrumbs":[{"docname":"intro/index","title":"Come iniziare","url":"/it/4.1/intro/"}],"prev":{"docname":"intro/tutorial04","title":"Scrivere la tua prima applicazione in Django, parte 4","url":"/it/4.1/intro/tutorial04/"},"next":{"docname":"intro/tutorial06","title":"Scrivere la tua prima applicazione in Django, parte 6","url":"/it/4.1/intro/tutorial06/"},"formats":{"html":"/it/4.1/intro/tutorial05/","markdown":"/it/4.1/intro/tutorial05.md","json":"/it/4.1/intro/tutorial05.json"},"source":"https://github.com/django/django/blob/stable/4.1.x/docs/intro/tutorial05.txt","official":"https://docs.djangoproject.com/it/4.1/intro/tutorial05/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}