diff --git a/README.md b/README.md
index 45e9d35498be2110a90b4b957154e7e2e299cead..f7ee06bf2c6819cbc8c97dc799ac9fc83787bb03 100644
--- a/README.md
+++ b/README.md
@@ -122,4 +122,270 @@ def test_input_todo(self):
- Digunakan variabel `MAX_WAIT` sebagai penanda batas waktu untuk melakukan *looping* menunggu halaman selesai di-*load*. Variabel ini bernilai 10 yang berarti 10 detik.
- Diberikan potongan kode `while True` dimana Selenium akan terus mengecek apakah terdapat kata `'Dummy'` dalam daftar tabel yang ditampilkan.
-- Diberikan *error handling* pada potongan kode `except (AssertionError, WebDriverException) as e` dimana dilakukan pengecekan apakah waktu yang berjalan sudah melebihi nilai `MAX_WAIT`. Jika sudah, maka kedua *exeption* tersebut akan di-*raise* dan test gagal. Sedangkan jika belum, akan dilakukan *sleep* selama 0.5 detik sebelum kembali melakukan pengecekan.
\ No newline at end of file
+- Diberikan *error handling* pada potongan kode `except (AssertionError, WebDriverException) as e` dimana dilakukan pengecekan apakah waktu yang berjalan sudah melebihi nilai `MAX_WAIT`. Jika sudah, maka kedua *exeption* tersebut akan di-*raise* dan test gagal. Sedangkan jika belum, akan dilakukan *sleep* selama 0.5 detik sebelum kembali melakukan pengecekan.
+
+## Penjelasan Tutorial 4
+
+Berdasarkan buku **Test-Driven Development with Python 2nd Edition,** tutorial ini memiliki beberapa keterkaitan dengan materi yang disajikan di bab 7 (**Working Incrementally**), diantaranya adalah sebagai berikut.
+
+- Implementasi *method*-*method* pada *unit test* untuk pengecekan *redirection* dan penggunaan *template file* oleh pada berkas `views.py`. Diantaranya sebagai berikut.
+
+ ```python
+ class Tutorial2UnitTest(TestCase):
+
+ def test_use_correct_template(self):
+ response = self.client.get('/tutorial-2/')
+ self.assertTemplateUsed(response, 'tutorial_2.html')
+
+ def test_can_save_POST_request_todo(self):
+ self.client.post(
+ '/tutorial-2/add_todo/',
+ data={
+ 'date': '2019-09-05T14:31',
+ 'activity': DUMMY_TODO_ITEM
+ }
+ )
+ todo_count = TodoList.objects.count()
+ new_todo = TodoList.objects.first()
+
+ self.assertEqual(todo_count, 1)
+ self.assertEqual(getattr(new_todo, 'todo_list'), DUMMY_TODO_ITEM)
+
+ def test_can_save_POST_request_todo_commentary(self):
+ self.client.post(
+ '/tutorial-2/add_todo_commentary/',
+ data={
+ 'date': '2019-09-12',
+ 'comment': DUMMY_TODO_COMMENTARY_ITEM
+ }
+ )
+ todo_commentary_count = TodoListCommentary.objects.count()
+ new_todo_commentary = TodoListCommentary.objects.first()
+
+ self.assertEqual(todo_commentary_count, 1)
+ self.assertEqual(getattr(new_todo_commentary, 'comment'), DUMMY_TODO_COMMENTARY_ITEM)
+
+ def test_redirects_after_POST_todo(self):
+ response = self.client.post(
+ '/tutorial-2/add_todo/',
+ data={
+ 'date': '2019-09-05T14:31',
+ 'activity': DUMMY_TODO_ITEM
+ }
+ )
+ self.assertEqual(response.status_code, 302)
+ self.assertRedirects(response, '/tutorial-2/')
+
+ def test_redirects_after_POST_todo_commentary(self):
+ response = self.client.post(
+ '/tutorial-2/add_todo_commentary/',
+ data={
+ 'date': '2019-09-12',
+ 'comment': DUMMY_TODO_COMMENTARY_ITEM
+ }
+ )
+ self.assertEqual(response.status_code, 302)
+ self.assertRedirects(response, '/tutorial-2/')
+ ```
+
+ Selain itu, saya juga menambahkan implementasi *unit tests* dengan menggunakan `LiveServerTestCase` yaitu sebuah *library* bawaan dari Django, sehingga saya tidak perlu menjalankan perintah `runserver` lagi.
+
+- Pengimplementasian *functional test* yang sudah disesuaikan dengan *unit test* yang diimplementasikan berdasarkan bab 7, sehingga ketika dijalankan *automated script* untuk *unit test* maupun *functional test*, berhasil.
+
+Selanjutnya, untuk pengimplementasian tutorial 4 ini, saya menambahkan **aesthetics test**, yaitu *functional testing* pada CSS dengan menggunakan modul `StaticLiveServerTestCase` yang merupakan bawaan dari Django. Berikut adalah salah satu contoh implementasinya.
+
+```python
+def test_layout_and_styling_todo_input_textbox(self):
+ selenium = self.selenium
+ selenium.get(self.host)
+ selenium.set_window_size(1024, 768)
+
+ todo_date = selenium.find_element_by_id('todo_date')
+ self.assertAlmostEqual(
+ todo_date.location['x'] + todo_date.size['width'] / 2,
+ 740,
+ delta=10
+ )
+
+def test_layout_and_styling_todo_commentary_input_textbox(self):
+ selenium = self.selenium
+ selenium.get(self.host)
+ selenium.set_window_size(1024, 768)
+
+ todo_commentary = selenium.find_element_by_id('comment_date')
+ self.assertAlmostEqual(
+ todo_commentary.location['x'] + todo_commentary.size['width'] / 2,
+ 780,
+ delta=10
+ )
+```
+
+Untuk *templating languange* pada HTML, saya sudah mengimplementasikan sebelumya, dimulai dari *app* `tutorial-1` dan `tutorial-2`
+
+````html
+{% load staticfiles %}
+
+
+