{"title":"Menulis aplikasi Django pertama anda, bagian 5","version":"3.1","locale":"id","docname":"intro/tutorial05","url":"/id/3.1/intro/tutorial05/","canonical":"https://djangodocs.dev/id/3.1/intro/tutorial05/","summary":"Tutorial ini mulai dimana Tutorial 4 ditinggalkan. Kami telah membangun aplikasi jejak pendapat jaringan, dan kami akan sekarang membuat otomatis percobaan…","html":"<h1>Menulis aplikasi Django pertama anda, bagian 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>Tutorial ini mulai dimana <a class=\"reference internal\" href=\"/id/3.1/intro/tutorial04/\"><span class=\"doc\">Tutorial 4</span></a> ditinggalkan. Kami telah membangun aplikasi jejak pendapat jaringan, dan kami akan sekarang membuat otomatis percobaan untuknya.</p>\n<aside class=\"admonition-where-to-get-help admonition\">\n<p class=\"admonition-title\">Dimana mendapatkan bantuan:</p>\n<p>Jika anda memiliki masalah melalui tutorial ini, harap geser ke <a class=\"reference internal\" href=\"/id/3.1/faq/help/\"><span class=\"doc\">Getting Help</span></a> bagian dari FAQ.</p>\n</aside>\n<section id=\"introducing-automated-testing\">\n<h2>Memperkenalkan percobaan otomatis<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>Apakah percobaan otomatis?<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>Percobaan adalah rutin yang memeriksa tindakan dari kode anda.</p>\n<p>Percobaan beroperasi di tingkatan berbeda. Beberapa percobaan mungkin berlaku ke rincian kecil (<em>apakah cara model khas mengembalikan nilai sesuai diharapkan?</em>) selama lainnya menguji operasi keseluruhan dari perangkat keras (<em>apakah urutan dari masukan pengguna di situs menghasilkan hasil yang diinginkan?</em>). Itu tidak berbeda dari beragam percobaan anda lakukan sebelumnya di <a class=\"reference internal\" href=\"/id/3.1/intro/tutorial02/\"><span class=\"doc\">Tutorial 2</span></a>, menggunakan <a class=\"reference internal\" href=\"/id/3.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> untuk menguji kebiasaan cara, atau menjalankan aplikasi dan memasukkan data untuk diperiksa bagaimana kebiasaannya.</p>\n<p>Apa perbedaan di percobaan <em>otomatis</em> dimana percobaan bekerja selesai untuk anda oleh sistem. Anda membuat kumpulan percobaan sekali, dan lalu ketika anda membuat perubahan ke aplikasi anda, anda dapat memeriksa kode anda masih bekerja seperti anda inginkan aslinya, tanpa harus melakukan percobaan manual memakan waktu.</p>\n</section>\n<section id=\"why-you-need-to-create-tests\">\n<h3>Mengapa anda butuh membuat percobaan<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>Jadi mengapa membuat percobaan, dan jenapa sekarang?</p>\n<p>Anda mungkin merasa bahwa anda sangat cukup hanya belajar Python/Django, dan tidak mempunyai hal lain untuk belajar dan melakukan nampak luar biasa dan mungkin tidak perlu. Setelah semua, aplikasi jejak pendapat bekerja sangat gembira sekarang; melalui masalah dari pembuatan percobaan otomatis tidak akan membuatnya bekerja lebih baik. Jika membuat aplikasi jejak pendapat adalah hal terakhir dari pemrograman Django anda pernah lakukan, lalu benar, anda tidak butuh membuat percobaan otomatis. Tetapi, jika itu bukan kasusnya, sekarang adalah waktu yang tepat untuk belajar.</p>\n<section id=\"tests-will-save-you-time\">\n<h4>Percobaan akan menyelematkan waktu anda<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>Sampai titik tertentu, 'memeriksa itu kelihatannya bekerja' akan menjadi percobaan memuaskan. Di lebih aplikasi menakjubkan, anda mungkin mempunyai lusinan interaksi rumit antara komponen.</p>\n<p>Kesempatan dalam tiap komponen tersebut dapat memiliki konsekuensi tidak diharapkan pada perilaku aplikasi. Memeriksa bahwa itu 'terlihat masih bekerja' dapat berarti berjalan melalui kegunaan kode anda dengan dua puluh ragam perbedaan dari percobaan data anda untuk memastikan ada belum memrusak sesuatu - bukan penggunaan bagus dari waktu anda.</p>\n<p>Itu terutama benar ketika percobaan otomatis dapat melakukan ini untuk anda dalam hitungan detik. Jika sesuatu berjalan salah, percobaan akan juga membantu mencirikan kode yang menyebabkan kebiasaan tidak diharapkan.</p>\n<p>Terkadang dia kelihatan bertugas untuk menyobek air mata anda jauh dari produktif anda, bekerja pemrograman kreatif untuk menghadapi bisnis tidak menarik dan tidak menggairahkan dari percobaan penulisan terutama ketika anda mengetahui kode anda bekerja dengan benar.</p>\n<p>Bagaimanapun, tugas dari menulis percobaan adalah banyak lebih mengisi daripada menghabiskan berjam-jam mencoba aplikasi anda secara manual atau mencoba mencirikan penyebab dari masalah baru yang diperkenalkan.</p>\n</section>\n<section id=\"tests-don-t-just-identify-problems-they-prevent-them\">\n<h4>Percobaan tidak hanya mencirikan masalah, mereka mencegah masalah<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>Adalah sebuah kesalahan berpikir percobaan hanya aspek negatif dari pengembangan.</p>\n<p>Tanpa percobaan, tujuan atau kebiasaan dimaksud dari aplikasi mungkin agak buram. Bahkan ketika itu kode anda sendiri, anda akan terkadang menemukan diri anda mangaduk-aduknya dan mencoba menemukan apa sebenarnya yang dia lakukan.</p>\n<p>Percobaan merubah itu; mereka menyalakan kode anda dari dalam, dan ketika sesuatu menjadi salah, mereka fokus menyalakan bagian yang berjalan salah - <em>bahkan jika anda belum menyadarinya telah berjalan salah</em>.</p>\n</section>\n<section id=\"tests-make-your-code-more-attractive\">\n<h4>Percobaan membuat kode anda lebih menarik<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>Anda mungkin telah membuat potongan perangkat keras hebat, tetapi anda akan menemukan bahwa pengembang lain akan menolat melihatnya karena itu kurang dicoba; tanpa dicoba, mereka tidak akan mempercayainya. Jacob Kaplan-Moss, satu dari pengembang asli Django, katakan &quot;Kode tanpa percobaan adalah rusak berdasarkan rancangan.&quot;</p>\n<p>Bahwa pengembang lain ingin melihat percobaan di perangkat lunak anda sebelum mereka mengambilnya secara sungguh-sungguh adalah alasan lain untuk anda untuk memulai menulis percobaan.</p>\n</section>\n<section id=\"tests-help-teams-work-together\">\n<h4>Percobaan membantu tim bekerja bersama<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>Titik sebelumnya ditulis dari sudut pandang dari pengembang tunggal merawat sebuah aplikasi. Aplikasi rumit akan dirawat oleh tim. Jaminan percobaan dimana rekan tidak sengaja merusak kode anda (dan bahwa anda tidak merusak kode mereka tanpa diketahui). Jika anda ingin membuat hidup seperti pemrogram Django, anda harus menjadi bagus pada penulisan percobaan!</p>\n</section>\n</section>\n</section>\n<section id=\"basic-testing-strategies\">\n<h2>Strategi percobaan dasar<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>Terdapat banyak cara untuk mendekatkan penulisan percobaan</p>\n<p>Beberapa pemrogram mengikuti disiplin dipanggil &quot;<a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Test-driven_development\">test-driven development</a>&quot;; mereka sebenarnya menulis percobaan mereka sebelum mereka menulis kode mereka. Ini mungkin terlihat kontra-intuitif, tetapi kenyataannya itu mirip pada apa kebanyakan orang akan sering lakukan: mereka menggambarkan masalah, kemudian membuat beberapa kode untuk menyelesaikannya. Pengembangan didorong-percobaan memformalkan masalah dalam kasus percobaan Python.</p>\n<p>Lebih sering, pendatang baru untuk mencoba akan membuat beberapa kode dan kemudan memutuskan bahwa itu harus mempunyai beberapa percobaan. Mungkin itu akan lebih baik untuk menulis beberapa percobaan lebih awal, tetapi itu tidak pernah terlampat untuk mulai.</p>\n<p>Terkadang adalah sangat sulit mencari tahu dimana untuk mulai dengan menulis percobaan. Jika anda telah menulis beberapa ribu baris Phyton, memilih sesuatu untuk dicoba mungkin tidak mudah. Di kasus seperti itu, adalah bermanfaat untuk menulis percobaan pertama anda lain kali anda membuat perubahan, salah satu anda menambahkan fitur atau memperbaiki kesalahan.</p>\n<p>Jadi mari kita melakukannya segera.</p>\n</section>\n<section id=\"writing-our-first-test\">\n<h2>Menulis percobaan pertama kami<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>Kami mencirikan kesalahan<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>Untungnya, terdapat kesalahan sedikit di aplikasi <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code> untuk kami perbaiki segera: cara <code class=\"docutils literal notranslate\"><span class=\"pre\">Question.was_published_recently()</span></code> mengembalikan <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> jika <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> telah diterbitkan dalam hari terakhir (yang benar) tetapi juga jika bidang <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> di masa depan (yang tentu tidak).</p>\n<p>Tegaskan kesalahan dengan menggunakan <a class=\"reference internal\" href=\"/id/3.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> untuk memeriksa metode pada sebuah pertanyaan dimana tanggal berbohong di masa datang:</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>Sejak hal-hal di masa depan tidak 'baru terjadi', hal ini jelaslah salah.</p>\n</section>\n<section id=\"create-a-test-to-expose-the-bug\">\n<h3>Buat percobaan untuk membuka kesalahan<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>Apa yang kita telah lakukan di <a class=\"reference internal\" href=\"/id/3.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> untuk mencoba masalah adalah sebenarnya kami dapat lakukan di percobaan otomatis, jadi mari kita rubah itu menjadi percobaan otomatis.</p>\n<p>Tempat biasa untuk percobaan aplikasi adalah di berkas aplikasi <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code>; sistem percobaan akan otomatis menemukan percobaan di berkas apapun yang namanya dimulai dengan <code class=\"docutils literal notranslate\"><span class=\"pre\">test</span></code>.</p>\n<p>Taruh berikut di berkas <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code> di aplikasi <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\">polls/tests.py</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>Disini kami telah membuat sebuah subkelas <a class=\"reference internal\" href=\"/id/3.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> dengan sebuah metode yang membuat sebuah contoh <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> dengan <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> di masa depan. Kami kemudian memeriksa keluaran dari <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently()</span></code> - yang <em>mungkin</em> menjadi False.</p>\n</section>\n<section id=\"running-tests\">\n<h3>Menjalankan percobaan<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>Pada terminal, kita dapat menjalankan percobaan kita:</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>dan anda akan lihat sesuatu seperti:</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\">Kesalahan berbeda?</p>\n<p>Jika sebaliknya anda mendapatkannya <code class=\"docutils literal notranslate\"><span class=\"pre\">NameError</span></code> disini, anda mungkin kehilangan langkah dalam <a class=\"reference internal\" href=\"/id/3.1/intro/tutorial02/#tutorial02-import-timezone\"><span class=\"std std-ref\">Part 2</span></a> dimana kami menambahkan import dari <code class=\"docutils literal notranslate\"><span class=\"pre\">datetime</span></code> dan <code class=\"docutils literal notranslate\"><span class=\"pre\">timezone</span></code> pada <code class=\"docutils literal notranslate\"><span class=\"pre\">polls/models.py</span></code>. Salin import dari bagian itu, dan coba jalankan percobaan anda kembali.</p>\n</aside>\n<p>Apa yang terjadi adalah ini:</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> untuk melihat percobaan pada aplikasi <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code></p></li>\n<li><p>itu menemukan subkelas dari kelas  <a class=\"reference internal\" href=\"/id/3.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>itu membuat basisdata khusus untuk tujuan percobaan</p></li>\n<li><p>Itu mencari cara percobaan - satu yang namanya dimulai dengan <code class=\"docutils literal notranslate\"><span class=\"pre\">test</span></code></p></li>\n<li><p>di <code class=\"docutils literal notranslate\"><span class=\"pre\">test_was_published_recently_with_future_question</span></code> dia membuat sebuah instance <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> yang bidang <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> adalah 30 hari di masa depan</p></li>\n<li><p>... dan menggunakan cara <code class=\"docutils literal notranslate\"><span class=\"pre\">assertIs()</span></code>, itu menemukan bahwa <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently()</span></code> mengembalikan <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code>, meskipun kami menginginkannya mengembalikan <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code>.</p></li>\n</ul>\n<p>Percobaan menginformasikan kami yang mana percobaan gagal dan bahkan baris di mana kegagalan muncul.</p>\n</section>\n<section id=\"fixing-the-bug\">\n<h3>Memperbaiki kesalahan<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>Kami sudah mengetahui bahwa masalahnya adalah: <code class=\"docutils literal notranslate\"><span class=\"pre\">Question.was_published_recently()</span></code> harus mengembalikan <code class=\"docutils literal notranslate\"><span class=\"pre\">False</span></code> jika <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> nya berada di masa depan. Merubah cara di <code class=\"docutils literal notranslate\"><span class=\"pre\">models.py</span></code>, sehingga dia hanya mengembalikan <code class=\"docutils literal notranslate\"><span class=\"pre\">True</span></code> jika tanggal juga berada di masa lampau:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/models.py</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>dan jalankan percobaan kembali:</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>Setelah mengenali sebuah bug, kami menulis tes untuk menemukannya dan memperbaiki bug yang ada di dalam kode sehingga tes yang kami buat dapat berjalan lancar.</p>\n<p>Banyak hal lain mungkin akan berjalan salah dengan aplikasi kami dimasa akan datang, tetapi kami yakin bahwa kami secara tidak sengaja memperkenalkan kembali kesalahan ini, karena menjalankan percobaan akan memperingati kami segera. Kami dapat membertimbangkan posi kecil ini dari aplikasi dijabarkan dengan aman selamanya</p>\n</section>\n<section id=\"more-comprehensive-tests\">\n<h3>Percobaan lebih luas<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>Selama kami disini, kami dapat lebih jauh berpikir cara <code class=\"docutils literal notranslate\"><span class=\"pre\">was_published_recently()</span></code>; kenyataannya, dia akan sangat memaslukan jika dalam memperbaiki satu kesalahan kami telah memunculkan yang lain.</p>\n<p>Tambah dua lagi cara percobaan ke kelas yang sama, untuk mencoba kebiasaan dari cara lebih menyeluruh:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/tests.py</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>Dan sekarang kami mempunyai tiga percobaan yang menegaskan bahwa <code class=\"docutils literal notranslate\"><span class=\"pre\">Question.was_published_recently()</span></code> mengembalikan nilai bijaksana untuk pertanyaan masa lampau, saat ini, dan masa depan.</p>\n<p>Kembali, <code class=\"docutils literal notranslate\"><span class=\"pre\">polls</span></code> adalah aplikasi minimal, tetapi bagaimanapun itu rumit tumbuh dimasa depan dan apapun kode lain itu berinteraksi, kami sekarang memiliki beberapa jaminan bahwa metode kami memiliki tes tertulis untuk akan berperilaku dengan cara yang diharapkan.</p>\n</section>\n</section>\n<section id=\"test-a-view\">\n<h2>Percobaan tampilan<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>Aplikasi jejak pendapat cukup tidak diskriminatif:  dia akan menerbitkan pertanyaan apapun, termasuk satu dimana bidang <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> terletak di masa depan. Kami harus meningkatkan ini. Pengaturan <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> di masa depan berarti bahwa Pertanyaan di terbitkan pada saat itu, tetapi tidak terlihat sampai saat itu.</p>\n<section id=\"a-test-for-a-view\">\n<h3>Sebuah percobaan untuk tampilan<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>Ketika kami memperbaiki kesalahan diatas, kami menulis percobaan pertama dulu dan kemudian kode untuk memperbaiki itu. Kenyataanya bahwa sebauh contoh dari pengembangan dikendalikan-percobaan, tapi itu tidak masalah bagaimana kita melakukan pekerjaan.</p>\n<p>Di percobaan pertama anda, kami fokus lebih dekat pada kebiasaan internal dari kode. Untuk percobaan ini, kami ingin memeriksa kebiasaannya seperti akan berpengalaman oleh pengguna melalui perambah jaringan.</p>\n<p>Sebelum kami mencoba memperbaiki apapun, mari kita melihat pada alat di pembuangan kami.</p>\n</section>\n<section id=\"the-django-test-client\">\n<h3>Klien percobaan 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 menyediakan percobaan <a class=\"reference internal\" href=\"/id/3.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> untuk menirukan antarmuka pengguna dengan kode di tingkatan tampilan. Kami dapat menggunakannya di <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code> atau bahkan di <a class=\"reference internal\" href=\"/id/3.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>Kami akan mulai kembali dengan <a class=\"reference internal\" href=\"/id/3.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a>, dimana kami butuh melakukan beberapa hal yang tidak diperlukan dalam <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code>. Pertama adalah mensetel lingkungan percobaan dalam <a class=\"reference internal\" href=\"/id/3.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=\"/id/3.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> memasang sebuah cetakan pembangun yang mana akan mengizinkan kami menguji beberapa atribut tambahan pada tanggapan seperti  <code class=\"docutils literal notranslate\"><span class=\"pre\">response.context</span></code> yang lain tidak akan tersedia. Catat bahwa cara ini <em>tidak</em> mengatur sebuah percobaan basis data, jadi berikut akan berjalan terhadap basisdata yang ada dan keluaran mungkin sedikit berbeda tergantung pada pertanyaan apa anda sudah buat. And mungkin mendapatkan hasil tidak diharapkan jika <code class=\"docutils literal notranslate\"><span class=\"pre\">TIME_ZONE</span></code> dalam <code class=\"docutils literal notranslate\"><span class=\"pre\">settings.py</span></code> tidak benar. Jika anda tidak mengingat pengaturannya terdahulu, periksa itu sebelum melanjutkan.</p>\n<p>Selanjutnya kami butuh mengimpor kelas klien percobaan (nanti di <code class=\"docutils literal notranslate\"><span class=\"pre\">tests.py</span></code> kami akan menggunakan kelas <a class=\"reference internal\" href=\"/id/3.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>, yang datang dengan klien sendirinya, jadi ini tidak akan diwajibkan):</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>Dengan itu siap, kami dapat meminta klien melakukan beberapa pekerjaan untuk kami:</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>Memperbaiki tampilan kami<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>Daftar jejak pendapat menunjukkan jejak pendapat yang belum diterbitkan (yaitu itu yang mempunyai <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> di masa depan). Mari kita perbaiki itu.</p>\n<p>Di <a class=\"reference internal\" href=\"/id/3.1/intro/tutorial04/\"><span class=\"doc\">Tutorial 4</span></a> kami memperkenalkan tampilan berdasarkan-kelas, berdasarkan pada <a class=\"reference internal\" href=\"/id/3.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\">polls/views.py</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>Kami butuh merubah cara <code class=\"docutils literal notranslate\"><span class=\"pre\">get_queryset()</span></code> dan merubahnya sehingga dia juga memeriksa tanggal dengan membandingkannya dengan <code class=\"docutils literal notranslate\"><span class=\"pre\">timezone.now()</span></code>. Pertama kami butuh menambahkan sebuah impor:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/views.py</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>dan lalu kami harus merubah cara <code class=\"docutils literal notranslate\"><span class=\"pre\">get_queryset</span></code> seperti begitu:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/views.py</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> mengembalikan queryset mengandung <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> dimana <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> kurang dari atau sama dengan - yaitu, lebih awal dari atau sama dengan - <code class=\"docutils literal notranslate\"><span class=\"pre\">timezone.now</span></code>.</p>\n</section>\n<section id=\"testing-our-new-view\">\n<h3>Menguji tampilan baru kami<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>Sekarang anda dapat memuaskan diri anda sendiri bahwa perilaku ini sesuai diharapkan dengan menyiapkan <code class=\"docutils literal notranslate\"><span class=\"pre\">runserver</span></code>, memuat situs dalam peramban anda, membuat <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> dengan tanggal dalam lampau dan masa datang, dan memeriksa bahwa hanya itu yang telah diterbitkan yang di daftarkan. Anda tidak ingin melakukan bahwa <em>setiap waktu anda membuat perubahan apapun yang mungkin mempengaruhi ini</em> -  jadi mari kita juga membuat percobaan, berdasarkan pada sesi <a class=\"reference internal\" href=\"/id/3.1/ref/django-admin/#django-admin-shell\"><code class=\"xref std std-djadmin docutils literal notranslate\"><span class=\"pre\">shell</span></code></a> kami diatas.</p>\n<p>Tambah berikut ke <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\">polls/tests.py</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>dan kami akan membuat fungsi jalan pintas untuk membuat pertanyaan dan juga kelas percobaan baru:</p>\n<figure class=\"code-block code-block-captioned\" data-language=\"python\"><figcaption class=\"code-block-caption\">polls/tests.py</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\">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=\"s1\">&#39;&lt;Question: Past question.&gt;&#39;</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\">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=\"s1\">&#39;&lt;Question: Past question.&gt;&#39;</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\">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\">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=\"s1\">&#39;&lt;Question: Past question 2.&gt;&#39;</span><span class=\"p\">,</span> <span class=\"s1\">&#39;&lt;Question: Past question 1.&gt;&#39;</span><span class=\"p\">]</span>\n        <span class=\"p\">)</span>\n</code></pre></figure>\n<p>Mari kita lihat beberapa ini lebih dekat.</p>\n<p>Pertama adalah fungsi jalan pintas pertanyaan, <code class=\"docutils literal notranslate\"><span class=\"pre\">create_question</span></code>, utuk mengambil beberapa perulangan dari pengolahan membuat pertanyaan.</p>\n<p><code class=\"docutils literal notranslate\"><span class=\"pre\">test_no_questions</span></code> tidak membuat pertanyaan apapun, tetapi periksa pesan: &quot;Tidak ada jejak pendapat tersedia.&quot; dan memeriksa <code class=\"docutils literal notranslate\"><span class=\"pre\">latest_question_list</span></code> adalah kosong. Catat bahwa kelas <a class=\"reference internal\" href=\"/id/3.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> menyediakan beberapa tambahan metode tuntutan. Dalam contoh ini, kami menggunakan <a class=\"reference internal\" href=\"/id/3.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> dan <a class=\"reference internal\" href=\"/id/3.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>Dalam <code class=\"docutils literal notranslate\"><span class=\"pre\">test_past_question</span></code>, kami membuat sebuah pertanyaan dan memeriksa bahwa jika itu muncul dalam daftar.</p>\n<p>Dalam <code class=\"docutils literal notranslate\"><span class=\"pre\">test_future_question</span></code>, kami membuat sebuah pertanyaan dengan <code class=\"docutils literal notranslate\"><span class=\"pre\">pub_date</span></code> di masa depan. Basisdata disetel kembali untuk setiap metode pengujian, jadi pertanyaan pertama tidak lagi disana, dan kembali indeks jangan mempunyai pertanyaan apapun di dalamnya.</p>\n<p>Dan sebagainya, Sebenarnya, kami menggunakan percobaan untuk memberitahu cerita masukan admin dan pengalaman pengguna di situs, dan memeriksa bahwa oada setiap tahapan dan setiap perubahan baru dari sistem, hasil yang diharapkan diterbitkan.</p>\n</section>\n<section id=\"testing-the-detailview\">\n<h3>Menguji <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>Apa yang telah kita kerjakan baik; meskipun pertanyaan masa depan tidak muncul di <em>indeks</em>, pengguna dapat masih mencapai mereka jika mereka tahu atau menebak URL yang tepat. Jadi kami butuh pembatas sama ke <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\">polls/views.py</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\">polls/tests.py</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>Ide untuk percobaan lebih<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>Kami seharusnya untuk menambahkan cara <code class=\"docutils literal notranslate\"><span class=\"pre\">get_queryset</span></code> mirip ke <code class=\"docutils literal notranslate\"><span class=\"pre\">ResultsView</span></code> dan membuat kelas percobaan baru untuk tampilan itu. Itu akan sangat mirip pada apa kami telah buat; faktanya akan ada banyak pengulangan.</p>\n<p>Kami dapat juga memperbaiki aplikasi kami di cara lain, menambahkan percobaan selama perjalanan. Sebagai contoh, adalah gila bahwa <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> dapat diterbitkan di situs yang tidak mempunyai <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code>. Jadi, tampilan kami dapat memeriksa untuk ini, dan tidak menyertakan <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> seperti itu. Percobaan kami akan membuat sebuah``Question`` tanpa <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code> dan lalu mencoba bahwa dia tidak diterbitkan, sama halnya membuat <code class=\"docutils literal notranslate\"><span class=\"pre\">Question</span></code> mirip <em>dengan</em> <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code>, dan mencoba bahwa <em>telah</em> diterbitkan.</p>\n<p>Mungkin pengguna admin masuk harus diizinkan melihat <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> tidak terbit, tetapi bukan asli pengunjung. Kembali: apapun kebutuhan untuk ditambahkan ke perangkat lunak untuk menyelesaikan ini harus disertai dengan percobaan, apakah anda menulis percobaan dahulu dan lalu membuat kode melewati percobaan, atau bekerja logis di kode anda pertama dan lalu menulis percobaan untuk membuktikannya.</p>\n<p>Pada beberapa titik anda terikat untuk melihat percobaan anda dan berharap apakah kode anda menderita dari percobaan gelembung, yang membawa kami kepada:</p>\n</section>\n</section>\n<section id=\"when-testing-more-is-better\">\n<h2>Ketika percobaan, lebih baik<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>Ini mungkin kelihatan bahwa percobaan kami tumbuh tidak terkendali. Pada tingkatan ini akan anda lebih kode di percobaan kami daripada di aplikasi kami, dan pengulangan tidak indah, dibandingkan ke keringkasan elegan dari sisa kode kami.</p>\n<p><strong>Itu tidak masalah</strong>. Biarkan mereka tumbuh. Untuk kebanyakan, anda dapat menulis percobaan sekali dan lalu melukapan tentang itu. Itu akan terus melakukan fungsi yang berguna ketika anda melanjutkan mengembangkan program anda.</p>\n<p>Terkadang percobaan akan butuh diperbaharui. Menduga itu kami merubah tampilan kami sehingga hanya <code class=\"docutils literal notranslate\"><span class=\"pre\">Questions</span></code> dengan <code class=\"docutils literal notranslate\"><span class=\"pre\">Choices</span></code> yang diterbitkan. Dalam kasus itu, banyak dari percobaan kami yang ada akan gagal - <a href=\"#id1\"><span class=\"problematic\" id=\"id2\">*</span></a>katakan ke kami tepatnya percobaan mana butuh dirubah untuk membawanya selalu terbaru, jadi pada tingkatan percobaan itu membantu menjaga diri mereka sendiri.</p>\n<p>Yang terburuk, ketika anda melanjutkan mengembangkan, anda mungkin menemukan bahwa anda mempunyai beberapa percobaan yang sekarang berlebihan. Bahkan itu bukan masalah; dalam percobaan adalah hal <em>bagus</em>.</p>\n<p>Selama percobaan anda menyadari diatur, mereka tidak akan menjadi tidak dapat diatur.  Aturan-dari-jempol bagis termasuk mempunyai:</p>\n<ul class=\"simple\">\n<li><p>terpisah <code class=\"docutils literal notranslate\"><span class=\"pre\">TestClass</span></code> untuk setiap model atau tampilan</p></li>\n<li><p>sebuah cara percobaan terpisah untuk setiap kumpulan kondisi anda ingin diuji</p></li>\n<li><p>Nama cara percobaan yang menggambarkan fungsi mereka</p></li>\n</ul>\n</section>\n<section id=\"further-testing\">\n<h2>Percobaan lebih jauh<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>Tutorial ini hanya memperkenalkan beberapa dasar dari percobaan. Terdapat urusan hebat anda dapat lakukan, dan sejumlah alat sangat berguna pada penyelesaian anda untuk mencapai beberapa hal sangat cakap.</p>\n<p>Sebagai contoh, selama percobaan kami telah dicakupi beberapa dari logika internal dari model dan cara tampilan kami menerbitkan informasi, anda dapat menggunakan kerangka &quot;di-perambah&quot; seperti <a class=\"reference external\" href=\"http://seleniumhq.org/\">Selenium</a> untuk mencoba cara HTML anda sebenarnya membangun di perambah. Alat ini mengizinkan anda untuk memeriksa bukan hanya kebiasaan kode Django, tetapi juga, sebagai contoh, dari Javascript anda. Ini cukup sesuatu untuk melihat percobaan meluncurkan perambah, dan mulai berinteraksi dengan situs anda, sebagai jika menjadi manusia mengemudikannya! Django menyertakan <a class=\"reference internal\" href=\"/id/3.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> untuk memfasilitasi dengan alat seperti Selenium.</p>\n<p>Jika anda mempunyai aplikasi rumit, anda mungkin ingin menjalankan percobaan otomatis dengan setiap penyerahan untuk tujuan dari <a class=\"reference external\" href=\"https://en.wikipedia.org/wiki/Continuous_integration\">perpaduan kelanjutan</a>, sehingga kendali kualitas itu sendiri - setidaknya sebagian - otomatis.</p>\n<p>Sebuah jalan bagus untuk menempatkan bagian belum dicoba dari aplikasi anda adalah memeriksa cakupan kode. Ini juga membantu mencirikan kode rapuh atau bahkan mati. Jika anda tidak dapat mencoba potongan kode, biasanya berarti kode harus diuraikan kembali atau dipindahkan. Cakupan akan membantu mencirikan kode mati. Lihat <a class=\"reference internal\" href=\"/id/3.1/topics/testing/advanced/#topics-testing-code-coverage\"><span class=\"std std-ref\">Perpaduan dengan coverage.py</span></a> untuk rincian.</p>\n<p>doc:Testing in Django &lt;/topics/testing/index&gt; mempunyai informasi luas tentang percobaan.</p>\n</section>\n<section id=\"what-s-next\">\n<h2>Apa Selanjutnya?<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>Untuk rincian penuh di percobaan, lihat <a class=\"reference internal\" href=\"/id/3.1/topics/testing/\"><span class=\"doc\">Percobaan di Django</span></a>.</p>\n<p>Ketika anda nyaman dengan percobaan tampilan Django, baca <a class=\"reference internal\" href=\"/id/3.1/intro/tutorial06/\"><span class=\"doc\">bagian 6 dari tutorial ini</span></a> untuk mempelajari tentang pengelolaan berkas statis.</p>\n</section>","rootId":"writing-your-first-django-app-part-5","toc":[{"title":"Memperkenalkan percobaan otomatis","anchor":"introducing-automated-testing","children":[{"title":"Apakah percobaan otomatis?","anchor":"what-are-automated-tests","children":[]},{"title":"Mengapa anda butuh membuat percobaan","anchor":"why-you-need-to-create-tests","children":[{"title":"Percobaan akan menyelematkan waktu anda","anchor":"tests-will-save-you-time","children":[]},{"title":"Percobaan tidak hanya mencirikan masalah, mereka mencegah masalah","anchor":"tests-don-t-just-identify-problems-they-prevent-them","children":[]},{"title":"Percobaan membuat kode anda lebih menarik","anchor":"tests-make-your-code-more-attractive","children":[]},{"title":"Percobaan membantu tim bekerja bersama","anchor":"tests-help-teams-work-together","children":[]}]}]},{"title":"Strategi percobaan dasar","anchor":"basic-testing-strategies","children":[]},{"title":"Menulis percobaan pertama kami","anchor":"writing-our-first-test","children":[{"title":"Kami mencirikan kesalahan","anchor":"we-identify-a-bug","children":[]},{"title":"Buat percobaan untuk membuka kesalahan","anchor":"create-a-test-to-expose-the-bug","children":[]},{"title":"Menjalankan percobaan","anchor":"running-tests","children":[]},{"title":"Memperbaiki kesalahan","anchor":"fixing-the-bug","children":[]},{"title":"Percobaan lebih luas","anchor":"more-comprehensive-tests","children":[]}]},{"title":"Percobaan tampilan","anchor":"test-a-view","children":[{"title":"Sebuah percobaan untuk tampilan","anchor":"a-test-for-a-view","children":[]},{"title":"Klien percobaan Django","anchor":"the-django-test-client","children":[]},{"title":"Memperbaiki tampilan kami","anchor":"improving-our-view","children":[]},{"title":"Menguji tampilan baru kami","anchor":"testing-our-new-view","children":[]},{"title":"Menguji DetailView","anchor":"testing-the-detailview","children":[]},{"title":"Ide untuk percobaan lebih","anchor":"ideas-for-more-tests","children":[]}]},{"title":"Ketika percobaan, lebih baik","anchor":"when-testing-more-is-better","children":[]},{"title":"Percobaan lebih jauh","anchor":"further-testing","children":[]},{"title":"Apa Selanjutnya?","anchor":"what-s-next","children":[]}],"breadcrumbs":[{"docname":"intro/index","title":"Mulai","url":"/id/3.1/intro/"}],"prev":{"docname":"intro/tutorial04","title":"Menulis aplikasi Django pertama anda, bagian 4","url":"/id/3.1/intro/tutorial04/"},"next":{"docname":"intro/tutorial06","title":"Menulis aplikasi Django pertama anda, bagian 6","url":"/id/3.1/intro/tutorial06/"},"formats":{"html":"/id/3.1/intro/tutorial05/","markdown":"/id/3.1/intro/tutorial05.md","json":"/id/3.1/intro/tutorial05.json"},"source":"https://github.com/django/django/blob/stable/3.1.x/docs/intro/tutorial05.txt","official":"https://docs.djangoproject.com/id/3.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","pt-br","ko","es","el","pl"]}