# Dokumentasi Django 5.2.8

# Menulis aplikasi Django pertama anda, bagian 5

Tutorial ini memulai dimana Tutorial 4 ditinggalkan. Kami telah membangun aplikasi poling jaringan, dan kami akan membuat beberapa pengujian otomatis untuk itu.

Dimana mendapatkan bantuan:

Jika anda memiliki masalah melalui tutorial ini, harap geser ke Getting Help bagian dari FAQ.

## Memperkenalkan percobaan otomatis

### Apakah percobaan otomatis?

Percobaan adalah rutin yang memeriksa tindakan dari kode anda.

Percobaan beroperasi di tingkatan berbeda. Beberapa percobaan mungkin berlaku ke rincian kecil (apakah cara model khas mengembalikan nilai sesuai diharapkan?) selama lainnya menguji operasi keseluruhan dari perangkat keras (apakah urutan dari masukan pengguna di situs menghasilkan hasil yang diinginkan?). Itu tidak berbeda dari beragam percobaan anda lakukan sebelumnya di Tutorial 2, menggunakan `shell` untuk menguji kebiasaan cara, atau menjalankan aplikasi dan memasukkan data untuk diperiksa bagaimana kebiasaannya.

Apa perbedaan di percobaan otomatis 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.

### Mengapa anda butuh membuat percobaan

Jadi mengapa membuat percobaan, dan jenapa sekarang?

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.

#### Percobaan akan menyelematkan waktu anda

Sampai titik tertentu, 'memeriksa itu kelihatannya bekerja' akan menjadi percobaan memuaskan. Di lebih aplikasi menakjubkan, anda mungkin mempunyai lusinan interaksi rumit antara komponen.

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.

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.

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.

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.

#### Percobaan tidak hanya mencirikan masalah, mereka mencegah masalah

Adalah sebuah kesalahan berpikir percobaan hanya aspek negatif dari pengembangan.

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.

Percobaan merubah itu; mereka menyalakan kode anda dari dalam, dan ketika sesuatu menjadi salah, mereka fokus menyalakan bagian yang berjalan salah - bahkan jika anda belum menyadarinya telah berjalan salah.

#### Percobaan membuat kode anda lebih menarik

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 "Kode tanpa percobaan adalah rusak berdasarkan rancangan."

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.

#### Percobaan membantu tim bekerja bersama

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!

## Strategi percobaan dasar

Terdapat banyak cara untuk mendekatkan penulisan percobaan

Some programmers follow a discipline called "test-driven development"; they actually write their tests before they write their code. This might seem counterintuitive, but in fact it's similar to what most people will often do anyway: they describe a problem, then create some code to solve it. Test-driven development formalizes the problem in a Python test case.

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.

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.

Jadi mari kita melakukannya segera.

## Menulis percobaan pertama kami

### Kami mencirikan kesalahan

Untungnya, terdapat kesalahan sedikit di aplikasi `polls` untuk kami perbaiki segera: cara `Question.was_published_recently()` mengembalikan `True` jika `Question` telah diterbitkan dalam hari terakhir (yang benar) tetapi juga jika bidang `pub_date` `Question` di masa depan (yang tentu tidak).

Tegaskan kesalahan dengan menggunakan `shell` untuk memeriksa metode pada sebuah pertanyaan dimana tanggal berbohong di masa datang:

/ 

    $ python manage.py shell

    ...\> py manage.py shell

    >>> import datetime
    >>> from django.utils import timezone
    >>> # create a Question instance with pub_date 30 days in the future
    >>> future_question = Question(pub_date=timezone.now() + datetime.timedelta(days=30))
    >>> # was it published recently?
    >>> future_question.was_published_recently()
    True

Sejak hal-hal di masa depan tidak 'baru terjadi', hal ini jelaslah salah.

### Buat percobaan untuk membuka kesalahan

Apa yang kita telah lakukan di `shell` untuk mencoba masalah adalah sebenarnya kami dapat lakukan di percobaan otomatis, jadi mari kita rubah itu menjadi percobaan otomatis.

Tempat biasa untuk percobaan aplikasi adalah di berkas aplikasi `tests.py`; sistem percobaan akan otomatis menemukan percobaan di berkas apapun yang namanya dimulai dengan `test`.

Taruh berikut di berkas `tests.py` di aplikasi `polls` :

`polls/tests.py`

    import datetime

    from django.test import TestCase
    from django.utils import timezone

    from .models import Question

    class QuestionModelTests(TestCase):
        def test_was_published_recently_with_future_question(self):
            """
            was_published_recently() returns False for questions whose pub_date
            is in the future.
            """
            time = timezone.now() + datetime.timedelta(days=30)
            future_question = Question(pub_date=time)
            self.assertIs(future_question.was_published_recently(), False)

Disini kami telah membuat sebuah subkelas `django.test.TestCase` dengan sebuah metode yang membuat sebuah contoh `Question` dengan `pub_date` di masa depan. Kami kemudian memeriksa keluaran dari `was_published_recently()` - yang mungkin menjadi False.

### Menjalankan percobaan

Pada terminal, kita dapat menjalankan percobaan kita:

/ 

    $ python manage.py test polls

    ...\> py manage.py test polls

and you'll see something like:

    Creating test database for alias 'default'...
    System check identified no issues (0 silenced).
    F
    ======================================================================
    FAIL: test_was_published_recently_with_future_question (polls.tests.QuestionModelTests)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "/path/to/djangotutorial/polls/tests.py", line 16, in test_was_published_recently_with_future_question
        self.assertIs(future_question.was_published_recently(), False)
    AssertionError: True is not False

    ----------------------------------------------------------------------
    Ran 1 test in 0.001s

    FAILED (failures=1)
    Destroying test database for alias 'default'...

Kesalahan berbeda?

Jika sebaliknya anda mendapatkannya `NameError` disini, anda mungkin kehilangan langkah dalam Part 2 dimana kami menambahkan import dari `datetime` dan `timezone` pada `polls/models.py`. Salin import dari bagian itu, dan coba jalankan percobaan anda kembali.

Apa yang terjadi adalah ini:

- `manage.py test polls` untuk melihat percobaan pada aplikasi `polls`

- itu menemukan subkelas dari kelas `django.test.TestCase`

- itu membuat basisdata khusus untuk tujuan percobaan

- Itu mencari cara percobaan - satu yang namanya dimulai dengan `test`

- di `test_was_published_recently_with_future_question` dia membuat sebuah instance `Question` yang bidang `pub_date` adalah 30 hari di masa depan

- ... dan menggunakan cara `assertIs()`, itu menemukan bahwa `was_published_recently()` mengembalikan `True`, meskipun kami menginginkannya mengembalikan `False`.

Percobaan menginformasikan kami yang mana percobaan gagal dan bahkan baris di mana kegagalan muncul.

### Memperbaiki kesalahan

Kami sudah mengetahui bahwa masalahnya adalah: `Question.was_published_recently()` harus mengembalikan `False` jika `pub_date` nya berada di masa depan. Merubah cara di `models.py`, sehingga dia hanya mengembalikan `True` jika tanggal juga berada di masa lampau:

`polls/models.py`

    def was_published_recently(self):
        now = timezone.now()
        return now - datetime.timedelta(days=1) <= self.pub_date <= now

and run the test again:

    Creating test database for alias 'default'...
    System check identified no issues (0 silenced).
    .
    ----------------------------------------------------------------------
    Ran 1 test in 0.001s

    OK
    Destroying test database for alias 'default'...

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.

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

### Percobaan lebih luas

Selama kami disini, kami dapat lebih jauh berpikir cara `was_published_recently()`; kenyataannya, dia akan sangat memaslukan jika dalam memperbaiki satu kesalahan kami telah memunculkan yang lain.

Tambah dua lagi cara percobaan ke kelas yang sama, untuk mencoba kebiasaan dari cara lebih menyeluruh:

`polls/tests.py`

    def test_was_published_recently_with_old_question(self):
        """
        was_published_recently() returns False for questions whose pub_date
        is older than 1 day.
        """
        time = timezone.now() - datetime.timedelta(days=1, seconds=1)
        old_question = Question(pub_date=time)
        self.assertIs(old_question.was_published_recently(), False)

    def test_was_published_recently_with_recent_question(self):
        """
        was_published_recently() returns True for questions whose pub_date
        is within the last day.
        """
        time = timezone.now() - datetime.timedelta(hours=23, minutes=59, seconds=59)
        recent_question = Question(pub_date=time)
        self.assertIs(recent_question.was_published_recently(), True)

Dan sekarang kami mempunyai tiga percobaan yang menegaskan bahwa `Question.was_published_recently()` mengembalikan nilai bijaksana untuk pertanyaan masa lampau, saat ini, dan masa depan.

Kembali, `polls` 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.

## Percobaan tampilan

Aplikasi jejak pendapat cukup tidak diskriminatif: dia akan menerbitkan pertanyaan apapun, termasuk satu dimana bidang `pub_date` terletak di masa depan. Kami harus meningkatkan ini. Pengaturan `pub_date` di masa depan berarti bahwa Pertanyaan di terbitkan pada saat itu, tetapi tidak terlihat sampai saat itu.

### Sebuah percobaan untuk tampilan

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.

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.

Sebelum kami mencoba memperbaiki apapun, mari kita melihat pada alat di pembuangan kami.

### Klien percobaan Django

Django provides a test `Client` to simulate a user interacting with the code at the view level. We can use it in `tests.py` or even in the `shell`.

Kami akan mulai kembali dengan `shell`, dimana kami butuh melakukan beberapa hal yang tidak diperlukan dalam `tests.py`. Pertama adalah mensetel lingkungan percobaan dalam `shell`:

/ 

    $ python manage.py shell

    ...\> py manage.py shell

    >>> from django.test.utils import setup_test_environment
    >>> setup_test_environment()

`setup_test_environment()` memasang sebuah pembangun cetakan yang akan mengizinkan kita menguji beberapa tambahan atribut pada tanggapan seperti `response.context` yang sebaliknya tidak akan tersedia. Catat bahwa metode ini tidak mensetel basisdata percobaan, sehingga berikut akan berjalan terhadap basisdata yang ada dan keluaran mungkin sedikit berbeda tergantung pada pertanyaan apa anda telah buat. Anda mungkin mendapatkan hasil yang tidak diharapkan jika `TIME_ZONE` dalam `settings.py` tidak benar. Jika anda tidak ingat menyetel itu di awal, periksa itu sebelum melanjutkan.

Next we need to import the test client class (later in `tests.py` we will use the `django.test.TestCase` class, which comes with its own client, so this won't be required):

    >>> from django.test import Client
    >>> # create an instance of the client for our use
    >>> client = Client()

With that ready, we can ask the client to do some work for us:

    >>> # get a response from '/'
    >>> response = client.get("/")
    Not Found: /
    >>> # we should expect a 404 from that address; if you instead see an
    >>> # "Invalid HTTP_HOST header" error and a 400 response, you probably
    >>> # omitted the setup_test_environment() call described earlier.
    >>> response.status_code
    404
    >>> # on the other hand we should expect to find something at '/polls/'
    >>> # we'll use 'reverse()' rather than a hardcoded URL
    >>> from django.urls import reverse
    >>> response = client.get(reverse("polls:index"))
    >>> response.status_code
    200
    >>> response.content
    b'\n    <ul>\n    \n        <li><a href="/polls/1/">What&#x27;s up?</a></li>\n    \n    </ul>\n\n'
    >>> response.context["latest_question_list"]
    <QuerySet [<Question: What's up?>]>

### Memperbaiki tampilan kami

Daftar jejak pendapat menunjukkan jejak pendapat yang belum diterbitkan (yaitu itu yang mempunyai `pub_date` di masa depan). Mari kita perbaiki itu.

Di Tutorial 4 kami memperkenalkan tampilan berdasarkan-kelas, berdasarkan pada `ListView`:

`polls/views.py`

    class IndexView(generic.ListView):
        template_name = "polls/index.html"
        context_object_name = "latest_question_list"

        def get_queryset(self):
            """Return the last five published questions."""
            return Question.objects.order_by("-pub_date")[:5]

Kami butuh merubah cara `get_queryset()` dan merubahnya sehingga dia juga memeriksa tanggal dengan membandingkannya dengan `timezone.now()`. Pertama kami butuh menambahkan sebuah impor:

`polls/views.py`

    from django.utils import timezone

dan lalu kami harus merubah cara `get_queryset` seperti begitu:

`polls/views.py`

    def get_queryset(self):
        """
        Return the last five published questions (not including those set to be
        published in the future).
        """
        return Question.objects.filter(pub_date__lte=timezone.now()).order_by("-pub_date")[
            :5
        ]

`Question.objects.filter(pub_date__lte=timezone.now())` returns a queryset containing `Question`s whose `pub_date` is less than or equal to - that is, earlier than or equal to - `timezone.now()`.

### Menguji tampilan baru kami

Now you can satisfy yourself that this behaves as expected by firing up `runserver`, loading the site in your browser, creating a few `Question` entries with dates in the past and future, and checking that only those that have been published are listed. You don't want to have to do that every single time you make any change that might affect this - so let's also create a test, based on our `shell` session above.

Tambah berikut ke `polls/tests.py`:

`polls/tests.py`

    from django.urls import reverse

dan kami akan membuat fungsi jalan pintas untuk membuat pertanyaan dan juga kelas percobaan baru:

`polls/tests.py`

    def create_question(question_text, days):
        """
        Create a question with the given `question_text` and published the
        given number of `days` offset to now (negative for questions published
        in the past, positive for questions that have yet to be published).
        """
        time = timezone.now() + datetime.timedelta(days=days)
        return Question.objects.create(question_text=question_text, pub_date=time)

    class QuestionIndexViewTests(TestCase):
        def test_no_questions(self):
            """
            If no questions exist, an appropriate message is displayed.
            """
            response = self.client.get(reverse("polls:index"))
            self.assertEqual(response.status_code, 200)
            self.assertContains(response, "No polls are available.")
            self.assertQuerySetEqual(response.context["latest_question_list"], [])

        def test_past_question(self):
            """
            Questions with a pub_date in the past are displayed on the
            index page.
            """
            question = create_question(question_text="Past question.", days=-30)
            response = self.client.get(reverse("polls:index"))
            self.assertQuerySetEqual(
                response.context["latest_question_list"],
                [question],
            )

        def test_future_question(self):
            """
            Questions with a pub_date in the future aren't displayed on
            the index page.
            """
            create_question(question_text="Future question.", days=30)
            response = self.client.get(reverse("polls:index"))
            self.assertContains(response, "No polls are available.")
            self.assertQuerySetEqual(response.context["latest_question_list"], [])

        def test_future_question_and_past_question(self):
            """
            Even if both past and future questions exist, only past questions
            are displayed.
            """
            question = create_question(question_text="Past question.", days=-30)
            create_question(question_text="Future question.", days=30)
            response = self.client.get(reverse("polls:index"))
            self.assertQuerySetEqual(
                response.context["latest_question_list"],
                [question],
            )

        def test_two_past_questions(self):
            """
            The questions index page may display multiple questions.
            """
            question1 = create_question(question_text="Past question 1.", days=-30)
            question2 = create_question(question_text="Past question 2.", days=-5)
            response = self.client.get(reverse("polls:index"))
            self.assertQuerySetEqual(
                response.context["latest_question_list"],
                [question2, question1],
            )

Mari kita lihat beberapa ini lebih dekat.

Pertama adalah fungsi jalan pintas pertanyaan, `create_question`, utuk mengambil beberapa perulangan dari pengolahan membuat pertanyaan.

`test_no_questions` doesn't create any questions, but checks the message: "No polls are available." and verifies the `latest_question_list` is empty. Note that the `django.test.TestCase` class provides some additional assertion methods. In these examples, we use `assertContains()` and `assertQuerySetEqual()`.

Dalam `test_past_question`, kami membuat sebuah pertanyaan dan memeriksa bahwa jika itu muncul dalam daftar.

Dalam `test_future_question`, kami membuat sebuah pertanyaan dengan `pub_date` 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.

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.

### Menguji `DetailView`

Apa yang telah kita kerjakan baik; meskipun pertanyaan masa depan tidak muncul di indeks, pengguna dapat masih mencapai mereka jika mereka tahu atau menebak URL yang tepat. Jadi kami butuh pembatas sama ke `DetailView`:

`polls/views.py`

    class DetailView(generic.DetailView):
        ...

        def get_queryset(self):
            """
            Excludes any questions that aren't published yet.
            """
            return Question.objects.filter(pub_date__lte=timezone.now())

Kami harus menambahkan beberapa percobaan, untuk memeriksa bahwa `Question` yang `pub_date` di masa lalu dapat ditampilkan, dan yang satu itu dengan `pub_date` di masa depan tidak:

`polls/tests.py`

    class QuestionDetailViewTests(TestCase):
        def test_future_question(self):
            """
            The detail view of a question with a pub_date in the future
            returns a 404 not found.
            """
            future_question = create_question(question_text="Future question.", days=5)
            url = reverse("polls:detail", args=(future_question.id,))
            response = self.client.get(url)
            self.assertEqual(response.status_code, 404)

        def test_past_question(self):
            """
            The detail view of a question with a pub_date in the past
            displays the question's text.
            """
            past_question = create_question(question_text="Past Question.", days=-5)
            url = reverse("polls:detail", args=(past_question.id,))
            response = self.client.get(url)
            self.assertContains(response, past_question.question_text)

### Ide untuk percobaan lebih

Kami seharusnya untuk menambahkan cara `get_queryset` mirip ke `ResultsView` dan membuat kelas percobaan baru untuk tampilan itu. Itu akan sangat mirip pada apa kami telah buat; faktanya akan ada banyak pengulangan.

We could also improve our application in other ways, adding tests along the way. For example, it's pointless that a `Question` with no related `Choice` can be published on the site. So, our views could check for this, and exclude such `Question` objects. Our tests would create a `Question` without a `Choice`, and then test that it's not published, as well as create a similar `Question` with at least one `Choice`, and test that it is published.

Perhaps logged-in admin users should be allowed to see unpublished `Question` entries, but not ordinary visitors. Again: whatever needs to be added to the software to accomplish this should be accompanied by a test, whether you write the test first and then make the code pass the test, or work out the logic in your code first and then write a test to prove it.

Pada beberapa titik anda terikat untuk melihat percobaan anda dan berharap apakah kode anda menderita dari percobaan gelembung, yang membawa kami kepada:

## Ketika percobaan, lebih baik

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.

Itu tidak masalah. 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.

Sometimes tests will need to be updated. Suppose that we amend our views so that only `Question` entries with associated `Choice` instances are published. In that case, many of our existing tests will fail - telling us exactly which tests need to be amended to bring them up to date, so to that extent tests help look after themselves.

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 bagus.

Selama percobaan anda menyadari diatur, mereka tidak akan menjadi tidak dapat diatur. Aturan-dari-jempol bagis termasuk mempunyai:

- terpisah `TestClass` untuk setiap model atau tampilan

- sebuah cara percobaan terpisah untuk setiap kumpulan kondisi anda ingin diuji

- Nama cara percobaan yang menggambarkan fungsi mereka

## Percobaan lebih jauh

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.

Sebagai contoh, selama percobaan kami telah dicakupi beberapa dari logika internal dari model dan cara tampilan kami menerbitkan informasi, anda dapat menggunakan kerangka "di-perambah" seperti Selenium 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 `LiveServerTestCase` untuk memfasilitasi dengan alat seperti Selenium.

Jika anda mempunyai aplikasi rumit, anda mungkin ingin menjalankan percobaan otomatis dengan setiap penyerahan untuk tujuan dari perpaduan kelanjutan, sehingga kendali kualitas itu sendiri - setidaknya sebagian - otomatis.

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 Perpaduan dengan coverage.py untuk rincian.

doc:Testing in Django </topics/testing/index> mempunyai informasi luas tentang percobaan.

## Apa Selanjutnya?

Untuk rincian penuh di percobaan, lihat Percobaan di Django.

Ketika anda nyaman dengan percobaan tampilan Django, baca bagian 6 dari tutorial ini untuk mempelajari tentang pengelolaan berkas statis.