{"title":"Escribiendo su primera aplicación en Django, parte 5","version":"4.1","locale":"es","docname":"intro/tutorial05","url":"/es/4.1/intro/tutorial05/","canonical":"https://djangodocs.dev/es/4.1/intro/tutorial05/","summary":"This tutorial begins where Tutorial 4 left off. We’ve built a web-poll application, and we’ll now create some automated tests for it. Dónde obtener ayuda: If you’re…","html":"<h1>Escribiendo su primera aplicación en 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>This tutorial begins where <a class=\"reference internal\" href=\"/es/4.1/intro/tutorial04/\"><span class=\"doc\">Tutorial 4</span></a> left off.\nWe’ve built a web-poll application, and we’ll now create some automated tests\nfor it.</p>\n<aside class=\"admonition-where-to-get-help admonition\">\n<p class=\"admonition-title\">Dónde obtener ayuda:</p>\n<p>If you’re having trouble going through this tutorial, please head over to\nthe <a class=\"reference internal\" href=\"/es/4.1/faq/help/\"><span class=\"doc\">Getting Help</span></a> section of the FAQ.</p>\n</aside>\n<section id=\"introducing-automated-testing\">\n<h2>Presentando las pruebas automatizadas<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>¿Qué son las pruebas automatizadas?<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>Tests are routines that check the operation of your code.</p>\n<p>Las pruebas se ejecutan en diferentes niveles. Algunas pruebas se pueden aplicar a un pequeño detalle (<em>¿Un método de modelo particular retorna valores como se espera?</em>) mientras que otras examinan el total funcionamiento del software (<em>¿Una secuencia de entradas de usuarios en el sitio produce el resultado deseado?</em>). No se diferencia del tipo de pruebas que ejecutó anteriormente en el <a class=\"reference internal\" href=\"/es/4.1/intro/tutorial02/\"><span class=\"doc\">Tutorial 2</span></a> utilizando el comando <a class=\"reference internal\" href=\"/es/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> para examinar el comportamiento de un método, o ejecutar la aplicación e ingresar datos para comprobar cómo se comporta.</p>\n<p>Lo que es diferente en las pruebas <em>automatizadas</em> es que el trabajo de pruebas por usted lo hace el sistema. Usted crea un conjunto de pruebas una vez, después, a medida que modifica su aplicación, puede comprobar que el código todavía funciona como originalmente lo concibió, sin necesidad de pruebas manuales engorrosas.</p>\n</section>\n<section id=\"why-you-need-to-create-tests\">\n<h3>El por qué es necesario crear pruebas<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>Entonces, ¿por qué crear pruebas y por qué ahora?</p>\n<p>Usted podría pensar que ya con aprender Python y Django tiene bastante con qué ocuparse, y que tener que aprender y hacer aún más cosas podría ser abrumador y hasta innecesario. Después de todo, nuestra aplicación encuestas está funcionando ahora bastante bien, tomarse la molestia de crear pruebas automatizadas no va a hacer que funcione mejor. Si crear la aplicación encuestas es el último fragmento de programa de Django que hará, entonces es verdad, usted no necesita saber cómo crear pruebas automatizadas. Sin embargo, si ese no es el caso, ahora es un momento excelente para aprender.</p>\n<section id=\"tests-will-save-you-time\">\n<h4>Las pruebas le ahorrarán tiempo<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>Hasta cierto punto, “comprobar de que parece funcionar” será una prueba satisfactoria. En una aplicación más sofisticada, es posible que tenga decenas de interacciones complejas entre los componentes.</p>\n<p>A change in any of those components could have unexpected consequences on the\napplication’s behavior. Checking that it still “seems to work” could mean\nrunning through your code’s functionality with twenty different variations of\nyour test data to make sure you haven’t broken something - not a good use\nof your time.</p>\n<p>Eso es especialmente cierto cuando las pruebas automatizadas pueden hacer esto por usted en cuestión de segundos. Si algo salió mal, las pruebas también ayudarán a identificar el código que está causando el comportamiento inesperado.</p>\n<p>A veces puede parecer un fastidio apartarse de su trabajo creativo y productivo de programación para afrontar la obligación poca atractiva y aburrida de escribir pruebas, particularmente cuando sabe que su código funciona de forma adecuada.</p>\n<p>Sin embargo, la tarea de escribir pruebas es mucho más gratificante que pasar horas probando su aplicación de forma manual o intentando identificar la causa de un problema recién introducido.</p>\n</section>\n<section id=\"tests-don-t-just-identify-problems-they-prevent-them\">\n<h4>Las pruebas no solo identifican los problemas, los previenen<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>Es un error pensar en las pruebas sólo como un aspecto negativo del desarrollo.</p>\n<p>Sin las pruebas, el propósito o el comportamiento previsto de una aplicación podría ser bastante incomprensible. Aún cuando es su propio código, usted a veces se encontrará buscando en él tratando de averiguar qué es exactamente lo que hace.</p>\n<p>Las pruebas cambian eso; iluminan su código desde adentro, y cuando algo sale mal, ellas se centran en la parte que salió mal; <em>incluso si usted no se ha dado cuenta de que salió mal</em>.</p>\n</section>\n<section id=\"tests-make-your-code-more-attractive\">\n<h4>Las pruebas hacen más atractivo su código<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>You might have created a brilliant piece of software, but you will find that\nmany other developers will refuse to look at it because it lacks tests; without\ntests, they won’t trust it. Jacob Kaplan-Moss, one of Django’s original\ndevelopers, says «Code without tests is broken by design.»</p>\n<p>Que otros desarrolladores quieran ver pruebas en su software antes de que se lo tomen en serio es una razón más para que usted comience a escribir las pruebas.</p>\n</section>\n<section id=\"tests-help-teams-work-together\">\n<h4>Las pruebas ayudan a los equipos a trabajar en conjunto<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>Los puntos anteriores están escritos desde el punto de vista de un único desarrollador que mantiene una aplicación. Las aplicaciones complejas serán mantenidas por equipos. Las pruebas garantizan que los colegas no rompan inadvertidamente su código (y que usted no rompa el de ellos sin saber). Si quiere ganarse la vida como un programador de Django, ¡Usted debe ser bueno escribiendo pruebas!</p>\n</section>\n</section>\n</section>\n<section id=\"basic-testing-strategies\">\n<h2>Estrategias básicas de pruebas<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>Hay muchas maneras de abordar la escritura de pruebas.</p>\n<p>Some programmers follow a discipline called «<a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Test-driven_development\">test-driven development</a>»; they\nactually write their tests before they write their code. This might seem\ncounter-intuitive, but in fact it’s similar to what most people will often do\nanyway: they describe a problem, then create some code to solve it. Test-driven\ndevelopment formalizes the problem in a Python test case.</p>\n<p>La mayoría de las veces, un principiante en pruebas va a crear código y luego decidirá que este debe tener algunas pruebas. Tal vez hubiera sido mejor escribir algunas pruebas antes, pero nunca es demasiado tarde para empezar.</p>\n<p>A veces es difícil saber por dónde empezar con la escritura de pruebas. Si usted ha escrito varias miles de líneas de Python, elegir algo para probar podría no ser fácil. En tal caso, es provechoso escribir su primera prueba la próxima vez que realice una modificación, ya sea cuando agregue una nueva funcionalidad o solucione un error.</p>\n<p>Así que vamos a hacer eso de inmediato.</p>\n</section>\n<section id=\"writing-our-first-test\">\n<h2>Escribiendo nuestra primera prueba<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>Identificamos un error<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>Afortunadamente, hay un pequeño error en la aplicación <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code> para que lo solucionemos de inmediato: el método <code class=\"docutils literal notranslate\"><span class=\"pre\">Question.was_published_recently()</span></code> retorna <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> si la <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> fue publicada en el último día (que es correcto), pero también si el campo de <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> de <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> está en el futuro (que de hecho no lo está).</p>\n<p>Confirm the bug by using the <a class=\"reference internal\" href=\"/es/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> to check the method on a question\nwhose date lies in the future:</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>Puesto que las cosas en el futuro no son “recientes”, esto es claramente erróneo.</p>\n</section>\n<section id=\"create-a-test-to-expose-the-bug\">\n<h3>Cree una prueba para exponer el error<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>Lo que acabamos de hacer en el comando <a class=\"reference internal\" href=\"/es/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> para detectar el problema es exactamente lo que podemos hacer en una prueba automatizada, así que vamos a convertir eso en una prueba automatizada.</p>\n<p>Un lugar convencional para las pruebas de una aplicación se encuentra en el archivo <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code> de la aplicación; el sistema de pruebas encontrará automáticamente las pruebas en cualquier archivo cuyo nombre comience con <code class=\"docutils literal notranslate\"><span class=\"pre\">test</span></code>.</p>\n<p>Ponga lo siguiente en el archivo <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code> de la aplicación <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>Here we have created a <a class=\"reference internal\" href=\"/es/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> subclass with a method that\ncreates a <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> instance with a <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> in the future. We then check\nthe output of <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently()</span></code> - which <em>ought</em> to be False.</p>\n</section>\n<section id=\"running-tests\">\n<h3>Ejecutando las pruebas<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>In the terminal, we can run our 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>y usted verá algo como:</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\">Different error?</p>\n<p>If instead you’re getting a <code class=\"docutils literal notranslate\"><span class=\"pre\">NameError</span></code> here, you may have missed a step\nin <a class=\"reference internal\" href=\"/es/4.1/intro/tutorial02/#tutorial02-import-timezone\"><span class=\"std std-ref\">Part 2</span></a> where we added imports of\n<code class=\"docutils literal notranslate\"><span class=\"pre\">datetime</span></code> and <code class=\"docutils literal notranslate\"><span class=\"pre\">timezone</span></code> to <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/models.py</span></code>. Copy the imports from\nthat section, and try running your tests again.</p>\n</aside>\n<p>Esto es lo que ocurrió:</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> looked for tests in the <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code> application</p></li>\n<li><p>encontró una subclase de la: clase: clase django.test.TestCase</p></li>\n<li><p>creó una base de datos especial para las pruebas</p></li>\n<li><p>buscó métodos de prueba; aquellos cuyos nombres comienzan con <code class=\"docutils literal notranslate\"><span class=\"pre\">test</span></code></p></li>\n<li><p>en <code class=\"docutils literal notranslate\"><span class=\"pre\">test_was_published_recently_with_future_question</span></code> creó una instancia <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> cuyo campo de <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> está 30 días en el futuro</p></li>\n<li><p>… y utilizando el método <code class=\"docutils literal notranslate\"><span class=\"pre\">assertIs()</span></code> descubrió que <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently()</span></code> retorna <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>, aunque queríamos que retornara <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code></p></li>\n</ul>\n<p>La prueba nos informa que prueba falló e incluso la línea en la que se produjo el error.</p>\n</section>\n<section id=\"fixing-the-bug\">\n<h3>Solucionando el error<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>Ya sabemos cuál es el problema: <code class=\"docutils literal notranslate\"><span class=\"pre\">Question.was_published_recently()</span></code> debe devolver <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code> si su <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> está en el futuro. Modifique el método <code class=\"docutils literal notranslate\"><span class=\"pre\">models.py</span></code>, de modo que este sólo retornará <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> si la fecha está también en el pasado:</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>y ejecute la prueba de nuevo:</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>Después de identificar un error, escribimos una prueba que lo expone y corregimos el error en el código para que nuestra prueba pase.</p>\n<p>Many other things might go wrong with our application in the future, but we can\nbe sure that we won’t inadvertently reintroduce this bug, because running the\ntest will warn us immediately. We can consider this little portion of the\napplication pinned down safely forever.</p>\n</section>\n<section id=\"more-comprehensive-tests\">\n<h3>Pruebas más exhaustivas<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>Ya que estamos aquí, podemos además precisar el método <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently()</span></code>; de hecho, sería verdaderamente vergonzoso si al corregir un error hubiéramos introducido otro.</p>\n<p>Agregue dos métodos de pruebas más a la misma clase, para probar el comportamiento del método de forma más completa:</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>Y ahora tenemos tres pruebas que confirman que <code class=\"docutils literal notranslate\"><span class=\"pre\">Question.was_published_recently()</span></code> retorna valores razonables para preguntas pasadas, recientes y futuras.</p>\n<p>Again, <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code> is a minimal application, but however complex it grows in the\nfuture and whatever other code it interacts with, we now have some guarantee\nthat the method we have written tests for will behave in expected ways.</p>\n</section>\n</section>\n<section id=\"test-a-view\">\n<h2>Pruebe 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>La aplicación encuestas no discrimina en lo absoluto: publicará cualquier pregunta, incluyendo aquellas cuyo campo de <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> esté en el futuro. Deberíamos actualizar esto. Establecer un <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> en el futuro debería significar que la pregunta se publica en ese momento, pero que será invisible hasta entonces.</p>\n<section id=\"a-test-for-a-view\">\n<h3>Una prueba para 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>When we fixed the bug above, we wrote the test first and then the code to fix\nit. In fact that was an example of test-driven development, but it doesn’t\nreally matter in which order we do the work.</p>\n<p>En nuestra primera prueba, nos centramos detalladamente en el comportamiento interno del código. Para esta prueba, queremos comprobar su comportamiento como lo experimentaría un usuario a través de un navegador web.</p>\n<p>Antes de tratar de corregir algo, echemos un vistazo a las herramientas a nuestra disposición.</p>\n</section>\n<section id=\"the-django-test-client\">\n<h3>El cliente de prueba de 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 proporciona una prueba <a class=\"reference internal\" href=\"/es/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> para simular un usuario interactúando con el código al nivel de la vista. Podemos utilizarlo en <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code> o incluso en el <a class=\"reference internal\" href=\"/es/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>We will start again with the <a class=\"reference internal\" href=\"/es/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a>, where we need to do a couple of\nthings that won’t be necessary in <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code>. The first is to set up the test\nenvironment in the <a class=\"reference internal\" href=\"/es/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=\"/es/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> installs a template renderer\nwhich will allow us to examine some additional attributes on responses such as\n<code class=\"docutils literal notranslate\"><span class=\"pre\">response.context</span></code> that otherwise wouldn’t be available. Note that this\nmethod <em>does not</em> set up a test database, so the following will be run against\nthe existing database and the output may differ slightly depending on what\nquestions you already created. You might get unexpected results if your\n<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> isn’t correct. If you don’t remember setting\nit earlier, check it before continuing.</p>\n<p>A continuación tenemos que importar la clase de cliente de prueba (más tarde en <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code> usaremos la clase <a class=\"reference internal\" href=\"/es/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> que viene con su propio cliente, por lo que esto no será necesario):</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>Con eso listo, podemos pedirle al cliente que haga un trabajo para nosotros:</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>Mejorando nuestra 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 de encuestas muestra las encuestas que aún no están publicadas (es decir, aquellas que tienen una <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> en el futuro). Vamos a solucionar eso.</p>\n<p>En el <a class=\"reference internal\" href=\"/es/4.1/intro/tutorial04/\"><span class=\"doc\">Tutorial 4</span></a> presentamos una vista basada en clases, basada en <a class=\"reference internal\" href=\"/es/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>Tenemos que modificar el método <code class=\"docutils literal notranslate\"><span class=\"pre\">get_queryset()</span></code> y cambiarlo para que también compruebe la fecha comparándolo con <code class=\"docutils literal notranslate\"><span class=\"pre\">timezone.now()</span></code>. En primer lugar tenemos que añadir 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>y luego hay que modificar el método <code class=\"docutils literal notranslate\"><span class=\"pre\">get_queryset</span></code> como sigue:</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> retorna un queryset que contiene <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code>s cuya <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> es menor o igual a, es decir, anterior o igual a <code class=\"docutils literal notranslate\"><span class=\"pre\">timezone.now</span></code>.</p>\n</section>\n<section id=\"testing-our-new-view\">\n<h3>Probando nuestra nueva 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>Now you can satisfy yourself that this behaves as expected by firing up\n<code class=\"docutils literal notranslate\"><span class=\"pre\">runserver</span></code>, loading the site in your browser, creating <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> with\ndates in the past and future, and checking that only those that have been\npublished are listed. You don’t want to have to do that <em>every single time you\nmake any change that might affect this</em> - so let’s also create a test, based on\nour <a class=\"reference internal\" href=\"/es/4.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> session above.</p>\n<p>Agregue lo siguiente 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>y vamos a crear una función de atajo para crear preguntas, así como una nueva clase de pruebas:</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>Veamos algunas de estas más de cerca.</p>\n<p>En primer lugar es una función de atajo a las preguntas, <code class=\"docutils literal notranslate\"><span class=\"pre\">create_question</span></code>, para eliminar parte de la repetición del proceso de creación de preguntas.</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">test_no_questions</span></code> no crea ninguna pregunta, pero comprueba el mensaje: «No hay encuestas disponibles.» y verifica que <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code> esté vacía. Tenga en cuenta que la clase <a class=\"reference internal\" href=\"/es/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> ofrece algunos métodos de aserción adicionales. En estos ejemplos utilizamos :meth:~django.test.SimpleTestCase.assertContains()` y <a class=\"reference internal\" href=\"/es/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>En <code class=\"docutils literal notranslate\"><span class=\"pre\">test_past_question</span></code> creamos una pregunta y verificamos que aparezca en la lista.</p>\n<p>En <code class=\"docutils literal notranslate\"><span class=\"pre\">test_future_question</span></code> creamos una pregunta con una <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> en el futuro. La base de datos se reinicia para cada método de prueba, por lo que la primera pregunta ya no está allí, de modo que de nuevo el índice no debería tener ninguna pregunta.</p>\n<p>Y así sucesivamente. En efecto, estamos utilizando las pruebas para contar una historia del ingreso de datos en el sitio administrativo y experiencia de usuario en el sitio, y comprobar que los resultados esperados se publican en cada estado y para cada nuevo cambio en el estado del sistema.</p>\n</section>\n<section id=\"testing-the-detailview\">\n<h3>Probando 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>Lo que tenemos funciona bien; sin embargo, a pesar de que las preguntas futuras no aparecen en el <em>índice</em>, los usuarios pueden todavía llegar a ellas si saben o adivinan la dirección URL correcta. Así que tenemos que agregar una restricción similar a la <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>We should then add some tests, to check that a <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> whose <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code>\nis in the past can be displayed, and that one with a <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> in the future\nis not:</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>Ideas para más pruebas<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>Debemos agregar un método <code class=\"docutils literal notranslate\"><span class=\"pre\">get_queryset</span></code> similar a <code class=\"docutils literal notranslate\"><span class=\"pre\">ResultsView</span></code> y crear una nueva clase de pruebas para esa vista. Va a ser muy similar a lo que acabamos de crear; de hecho, habrá mucha repetición.</p>\n<p>También podríamos mejorar nuestra aplicación de otras maneras, agregando pruebas a lo largo del camino. Por ejemplo, es una tontería que se puedan publicar <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> en el sitio que no tienen <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code>. Por lo tanto, nuestras vistas podrían comprobar esto y excluir dichas <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code>. Nuestras pruebas crearían una <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> sin <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code> y luego probarían que no está publicada, así como crearían una <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> similar <em>con</em> <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code> y probarían que <em>está</em> publicada.</p>\n<p>Quizás se les debería permitir a los usuarios registrados en el sitio administrativo ver las <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> que no han sido publicadas, pero no a los visitantes ordinarios. Una vez más: lo que se tenga que agregar al software para lograr esto debería ir acompañado de una prueba, ya sea que escriba la prueba primero y luego haga que el código pase la prueba, o primero solucione la lógica en el código y luego escriba una prueba para probarlo.</p>\n<p>En un momento dado usted está obligado a examinar sus pruebas y a preguntarse si su código sufre de exceso de pruebas, lo que nos lleva a:</p>\n</section>\n</section>\n<section id=\"when-testing-more-is-better\">\n<h2>Cuando se trata de pruebas, más es mejor<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>Podría parecer que nuestras pruebas están creciendo fuera de control. A este paso pronto habrá más código en nuestras pruebas que en nuestra aplicación y la repetición es poco estética en comparación con la refinada concisión del resto de nuestro código.</p>\n<p><strong>No importa</strong>, deje que crezcan. Por lo general, usted puede escribir una prueba una vez y luego olvidarse de ella. Esta seguirá cumpliendo su función útil mientras usted continúe desarrollando su programa.</p>\n<p>A veces las pruebas tendrán que ser actualizadas. Supongamos que modificamos nuestras vistas de modo que sólo las <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> con <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code> se publiquen. En ese caso, muchas de nuestras pruebas existentes fallarán, <em>indicándonos exactamente qué pruebas necesitan ser modificadas para actualizarlas</em>, de modo que hasta ese punto las pruebas ayudan a ocuparse de sí mismas.</p>\n<p>En el peor de los casos, a medida que continúe desarrollando, usted podría encontrar que tiene algunas pruebas que ahora son redundantes. Incluso eso no es un problema, cuando se trata de pruebas, la redundancia es algo <em>bueno</em>.</p>\n<p>Siempre y cuando las pruebas se organicen de forma razonable, no van a ser difíciles de manejar. Las reglas básicas de uso incluyen el hecho de tener:</p>\n<ul class=\"simple\">\n<li><p>una <code class=\"docutils literal notranslate\"><span class=\"pre\">TestClass</span></code> independiente para cada modelo o vista</p></li>\n<li><p>un método de prueba independiente para cada conjunto de condiciones que usted quiere probar</p></li>\n<li><p>nombres de los métodos de prueba que describan su función</p></li>\n</ul>\n</section>\n<section id=\"further-testing\">\n<h2>Pruebas adicionales<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>Este tutorial sólo presenta algunos de los temas fundamentales de las pruebas. Hay mucho más que usted puede hacer y una serie de herramientas muy útiles a su disposición para lograr algunas cosas muy interesantes.</p>\n<p>Por ejemplo, aunque nuestras pruebas han tratado aquí algo de la lógica interna de un modelo y la forma en que nuestras vistas publican información, usted puede utilizar un framework «en el navegador» como <a class=\"reference external\" href=\"https://www.selenium.dev/\">Selenium</a> para probar la forma en que su HTML en realidad se renderiza en un navegador. Estas herramientas le permiten comprobar no sólo el comportamiento de su código Django, sino también, por ejemplo, el de su JavaScript. ¡Es impresionante ver cómo las pruebas ejecutan un navegador y comienzan a interactuar con su sitio como si estuviese siendo operado por un humano! Django incluye <a class=\"reference internal\" href=\"/es/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> para facilitar la integración con herramientas como Selenium.</p>\n<p>Si usted tiene una aplicación compleja, es posible que desee ejecutar las pruebas de forma automática con cada commit a efectos de la integración continua_, por lo que el control de calidad está en sí, al menos parcialmente, automatizado.</p>\n<p>Una buena manera de detectar las partes de su aplicación que no han sido probadas es comprobar la cobertura de código. Esto también ayuda a identificar el código frágil o incluso muerto. Si no puede probar un trozo de código, por lo general significa que el código debe ser reestructurado o eliminado. La cobertura ayudará a identificar el código muerto. Consulte <a class=\"reference internal\" href=\"/es/4.1/topics/testing/advanced/#topics-testing-code-coverage\"><span class=\"std std-ref\">Integration with coverage.py</span></a> para más detalles.</p>\n<p><a class=\"reference internal\" href=\"/es/4.1/topics/testing/\"><span class=\"doc\">Las pruebas en Django</span></a> tiene información completa acerca de las pruebas.</p>\n</section>\n<section id=\"what-s-next\">\n<h2>¿Qué sigue?<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>Para más detalles sobre las pruebas, consulte <a class=\"reference internal\" href=\"/es/4.1/topics/testing/\"><span class=\"doc\">Las pruebas en Django</span></a>.</p>\n<p>Cuando esté familiarizado con las pruebas de las vistas de Django, lea la <a class=\"reference internal\" href=\"/es/4.1/intro/tutorial06/\"><span class=\"doc\">parte 6 de este tutorial</span></a> para aprender sobre la gestión de los archivos estáticos.</p>\n</section>","rootId":"writing-your-first-django-app-part-5","toc":[{"title":"Presentando las pruebas automatizadas","anchor":"introducing-automated-testing","children":[{"title":"¿Qué son las pruebas automatizadas?","anchor":"what-are-automated-tests","children":[]},{"title":"El por qué es necesario crear pruebas","anchor":"why-you-need-to-create-tests","children":[{"title":"Las pruebas le ahorrarán tiempo","anchor":"tests-will-save-you-time","children":[]},{"title":"Las pruebas no solo identifican los problemas, los previenen","anchor":"tests-don-t-just-identify-problems-they-prevent-them","children":[]},{"title":"Las pruebas hacen más atractivo su código","anchor":"tests-make-your-code-more-attractive","children":[]},{"title":"Las pruebas ayudan a los equipos a trabajar en conjunto","anchor":"tests-help-teams-work-together","children":[]}]}]},{"title":"Estrategias básicas de pruebas","anchor":"basic-testing-strategies","children":[]},{"title":"Escribiendo nuestra primera prueba","anchor":"writing-our-first-test","children":[{"title":"Identificamos un error","anchor":"we-identify-a-bug","children":[]},{"title":"Cree una prueba para exponer el error","anchor":"create-a-test-to-expose-the-bug","children":[]},{"title":"Ejecutando las pruebas","anchor":"running-tests","children":[]},{"title":"Solucionando el error","anchor":"fixing-the-bug","children":[]},{"title":"Pruebas más exhaustivas","anchor":"more-comprehensive-tests","children":[]}]},{"title":"Pruebe una vista","anchor":"test-a-view","children":[{"title":"Una prueba para una vista","anchor":"a-test-for-a-view","children":[]},{"title":"El cliente de prueba de Django","anchor":"the-django-test-client","children":[]},{"title":"Mejorando nuestra vista","anchor":"improving-our-view","children":[]},{"title":"Probando nuestra nueva vista","anchor":"testing-our-new-view","children":[]},{"title":"Probando la DetailView","anchor":"testing-the-detailview","children":[]},{"title":"Ideas para más pruebas","anchor":"ideas-for-more-tests","children":[]}]},{"title":"Cuando se trata de pruebas, más es mejor","anchor":"when-testing-more-is-better","children":[]},{"title":"Pruebas adicionales","anchor":"further-testing","children":[]},{"title":"¿Qué sigue?","anchor":"what-s-next","children":[]}],"breadcrumbs":[{"docname":"intro/index","title":"Empezando","url":"/es/4.1/intro/"}],"prev":{"docname":"intro/tutorial04","title":"Escribiendo su primera aplicación en Django, parte 4","url":"/es/4.1/intro/tutorial04/"},"next":{"docname":"intro/tutorial06","title":"Escribiendo su primera aplicación en Django, parte 6","url":"/es/4.1/intro/tutorial06/"},"formats":{"html":"/es/4.1/intro/tutorial05/","markdown":"/es/4.1/intro/tutorial05.md","json":"/es/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/es/4.1/intro/tutorial05/","inVersions":["6.1","6.0","5.2","5.1","5.0","4.2","4.1","4.0","3.2","3.1","3.0","2.2","2.1","2.0","1.11","1.10","1.9"],"inLocales":["en","zh-hans","fr","ja","id","it","pt-br","ko","es","el","pl"]}