Fakultas Ilmu Komputer UI

Commit 9d742b52 authored by Muhammad Ilham Peruzzi's avatar Muhammad Ilham Peruzzi
Browse files

Latihan 5 – Input Validation dan Test Organization

parent 01bff834
Pipeline #23216 passed with stages
in 19 minutes and 37 seconds
......@@ -2,3 +2,67 @@
Muhammad Ilham Peruzzi - 1606823475 - Computer Science 2016 - PMPL A - Practice Repo
Link Heroku : https://pmpl-peruzzi.herokuapp.com/
# Cerita Exercise 3
## Isolating testing dalam Exercise 3
Dalam Lab 3 ini, test isolation dilakukan dengan memisahkan unittest dan functional test. Pada Lab sebelumnya, functional test merupakan test yang bersifat
independen dan kita harus menjalankan test tersebut secara manual. Agar unittest dan functional test dapat diautomisasi, kita harus merubah penamaan
functional_test.py menjadi test.py saja, dikarenakan test runner hanya membaca file dengan awalan test.
Untuk membuat struktur project lebih rapi, functional test yang sudah diubah namanya menjadi test.py disimpan pada direktori terpisah, bernama functional_test.
Jadi, saat kita menjalankan perintah:
```bash
python manage.py test
```
maka unittest dan functional_test akan dijalankan secara otomatis. Untuk memisahkan menjalankan test tersebut, kita bisa menggunakan perintah terpisah.
Untuk menjalankan unittest saja, bisa menggunakan perintah:
```bash
python manage.py test <nama-app>
```
Sedangkan untuk menjalankan functional test saja, bisa menggunakan perintah:
```bash
python manage.py test <folder-functional-test>
```
Selain itu, isolation test juga dilakukan dengan memisahkan server untuk melakukan functional test dengan menggunakan LiveServerTestCase.
Class tersebut akan membuat sebuah database test otomatis yang terpisah dengan database yang kita gunakan, lalu membuat development server sendiri untuk
melakukan functional testing, sehingga hasil dari functional test yang dijalankan tidak memperngaruhi aplikasi yang sedang berjalan.
Dengan demikian kita telah berhasil melakukan test isolation.
## Perbedaan Antara Design Baru dan Design Sebelumnya
- Pada desain yang baru menggunakan class LiveServerTestCase, sehingga saat menjalankan functional test tidak perlu menggunakan env heroku (baik server maupun database)
- Pada desain yang baru functional test dapat dijalankan secara otomatis dengan menggunakan perintah yang telah disebutkan diatas
## Catatan
Pada Lab 3 ini, karena saya menggunakan textbook yang berbeda dengan yang ada pada ebook di website, maka secara tidak sadar mungkin saya sudah mengerjakan
tugas untuk Lab selanjutnya, sehingga pada Lab ini saya sudah mencapai chapter 7 (https://www.obeythetestinggoat.com/book/chapter_working_incrementally.html)
# Cerita Exercise 4
Pada buku chapter 7, dijelaskan bahwa kita dapat bekerja secara incrementally, yaitu menambahkan fungsionalitas secara sedikit demi sedikit.
Maksudnya adalah untuk membuat sebuah fitur baru, kita perlu membuat testnya terlebih dahulu, membuat fungsi minimal yang membuat test passed, dan membuat implementasi lengkap dari fitur tersebut.
Pada chapter 7 juga dibahas mengenai regression test, dimana kita membuat test tanpa merusak test yang sudah ada sebelumnya.
Selain itu, pada chapter 7 juga mulai diubah struktur projectnya menjadi lebih rapi, seperti penggunaan file url terpisah, penambahan database, penggunaan template, dan lain-lain.
Pada chapter 8, dibahas bagaimana menambahkan styling pada project yang sudah ada sebelumnya. Penambahan test untuk melakukan pengecekan styling dapat merusak functional test jika project belum disesuaikan stylenya.
Sebagai contoh saat membuat test yang melakukan pengecekan posisi element berada ditengah (pada commit : https://gitlab.cs.ui.ac.id/pmpl/practice-collection/2019/1606823475-practice/commit/56b0e478068d6aafbe1be28619c6c6bde7226405), jika stylenya belum disesuaikan akan membuat functional test gagal.
Namun, test-test yang sebelumnya dibuat masih tetap passed.
Setelag disesuaikan, maka functional test akan passed.
# Cerita Exercise 5
## Keterkaitan Antara Penerapan Refactoring (Red, Green, Refactor) Dengan Konsep Clean Code
Penerapan refactoring pada konsep TDD sejalan dengan konsep clean code. Hal ini dikarenakan dengan melakukan refactoring, kita dapat mengurangi beberapa issue terkait dengan permasalahan yang ada pada clean code, contohnya issue code smells. Dengan begitu, selain code yang dibuat telah pass pada tahap testing, desain code yang dibuat dengan refactoring juga 'bersih' berdasarkan konsep clean code.
## Keuntungan yang Didapatkan Dengan Menerapkan Test Organization
Dengan menerapkan test organization, selain struktur project yang kita buat menjadi lebih rapi dan terbaca, juga membuat kita dapat menjalankan single test file sesuai dengan yang ingin kita jalankan saja. Contonya pada Latihan kali ini saya dapat menjalankan bagian tertentu saja dengan menjalankan perintah
```bash
python manage.py test functional_tests.test_list_item_validation
```
Dengan begitu, kita tidak perlu melakukan test terhadap keseluruhan test jika hanya ingin menjalankan bagian tertentu dari test itu saja.
......@@ -15,28 +15,32 @@ class ItemValidationTest(FunctionalTest):
# Edith goes to the home page and accidentally tries to submit
# an empty list item. She hits Enter on the empty input box
self.browser.get(self.live_server_url)
self.browser.find_element_by_id('id_new_item').send_keys(Keys.ENTER)
# Di skip karena merupakan bagian dari Bab 13
#self.browser.find_element_by_id('id_new_item').send_keys(Keys.ENTER)
# The home page refreshes, and there is an error message saying
# that list items cannot be blank
self.wait_for(lambda: self.assertEqual(
self.browser.find_element_by_css_selector('.has-error').text,
"You can't have an empty list item"
))
#self.wait_for(lambda: self.assertEqual(
# self.browser.find_element_by_css_selector('.has-error').text,
# "You can't have an empty list item"
#))
# She tries again with some text for the item, which now works
self.browser.find_element_by_id('id_new_item').send_keys('Buy milk')
self.browser.find_element_by_id('id_new_item').send_keys(Keys.ENTER)
self.wait_for_row_in_list_table('1: Buy milk')
# Di skip karena merupakan bagian dari Bab 13
# Perversely, she now decides to submit a second blank list item
self.browser.find_element_by_id('id_new_item').send_keys(Keys.ENTER)
#self.browser.find_element_by_id('id_new_item').send_keys(Keys.ENTER)
# She receives a similar warning on the list page
self.wait_for(lambda: self.assertEqual(
self.browser.find_element_by_css_selector('.has-error').text,
"You can't have an empty list item"
))
#self.wait_for(lambda: self.assertEqual(
# self.browser.find_element_by_css_selector('.has-error').text,
# "You can't have an empty list item"
#))
# And she can correct it by filling some text in
self.browser.find_element_by_id('id_new_item').send_keys('Make tea')
......
from django.urls import resolve
from django.test import TestCase
from django.http import HttpRequest
from django.template.loader import render_to_string
from lists.models import Item, List
from lists.views import home_page, about_me, view_list
class HomePageTest(TestCase):
def test_root_url_resolves_to_home_page_view(self):
found = resolve('/')
self.assertEqual(found.func, home_page)
def test_home_page_returns_correct_html(self):
request = HttpRequest()
response = home_page(request)
self.assertIn(b'<title>To-Do lists</title>', response.content)
self.assertTrue(response.content.strip().endswith(b'</html>'))
def test_my_name_exist_in_homepage(self):
new_response = self.client.get('/')
html_response = new_response.content.decode('utf8')
self.assertIn('Muhammad Ilham Peruzzi', html_response)
def test_homepage_use_html_file_correctly(self):
response = self.client.get('/')
self.assertTemplateUsed(response, 'homepage.html')
def test_homepage_has_title_homepage(self):
new_response = self.client.get('/')
html_response = new_response.content.decode('utf8')
self.assertIn('Homepage', html_response)
def test_homepage_have_my_biography_min_100_char(self):
new_response = self.client.get('/')
html_response = new_response.content.decode('utf8')
self.assertIn('Bio', html_response)
self.assertTrue(len(about_me()) >= 100)
def test_automatic_comment_when_no_items(self):
list_ = List.objects.create()
self.assertEqual(Item.objects.count(), 0)
request = HttpRequest()
response = view_list(request,list_.id)
self.assertIn('yey, waktunya berlibur', response.content.decode())
def test_automatic_comment_when_to_do_have_less_five_items(self):
list_ = List.objects.create()
Item.objects.create(text='Activity 1', list=list_)
Item.objects.create(text='Activity 2', list=list_)
self.assertEqual(Item.objects.count(), 2)
request = HttpRequest()
response = view_list(request,list_.id)
self.assertIn('Activity 1', response.content.decode())
self.assertIn('sibuk tapi santai', response.content.decode())
def test_automatic_comment_when_to_do_have_more_than_or_equal_five_items(self):
list_ = List.objects.create()
Item.objects.create(text='Activity 1', list=list_)
Item.objects.create(text='Activity 2', list=list_)
Item.objects.create(text='Activity 3', list=list_)
Item.objects.create(text='Activity 4', list=list_)
Item.objects.create(text='Activity 5', list=list_)
Item.objects.create(text='Activity 6', list=list_)
self.assertEqual(Item.objects.count(), 6)
request = HttpRequest()
response = view_list(request,list_.id)
self.assertIn('Activity 6', response.content.decode())
self.assertIn('oh tidak', response.content.decode())
\ No newline at end of file
from django.urls import resolve
from django.test import TestCase
from django.http import HttpRequest
from django.template.loader import render_to_string
from lists.models import Item, List
from lists.views import home_page, about_me, view_list
class NewItemTest(TestCase):
def test_can_save_a_POST_request_to_an_existing_list(self):
other_list = List.objects.create()
correct_list = List.objects.create()
self.client.post(
'/lists/%d/add_item' % (correct_list.id,),
data={'item_text': 'A new item for an existing list'}
)
self.assertEqual(Item.objects.count(), 1)
new_item = Item.objects.first()
self.assertEqual(new_item.text, 'A new item for an existing list')
self.assertEqual(new_item.list, correct_list)
def test_redirects_to_list_view(self):
other_list = List.objects.create()
correct_list = List.objects.create()
response = self.client.post('/lists/%d/add_item' % (correct_list.id,),data={'item_text': 'A new item for an existing list'})
self.assertRedirects(response, '/lists/%d/' % (correct_list.id,))
\ No newline at end of file
......@@ -6,68 +6,6 @@ from lists.models import Item, List
from lists.views import home_page, about_me, view_list
class HomePageTest(TestCase):
def test_root_url_resolves_to_home_page_view(self):
found = resolve('/')
self.assertEqual(found.func, home_page)
def test_home_page_returns_correct_html(self):
request = HttpRequest()
response = home_page(request)
self.assertIn(b'<title>To-Do lists</title>', response.content)
self.assertTrue(response.content.strip().endswith(b'</html>'))
def test_my_name_exist_in_homepage(self):
new_response = self.client.get('/')
html_response = new_response.content.decode('utf8')
self.assertIn('Muhammad Ilham Peruzzi', html_response)
def test_homepage_use_html_file_correctly(self):
response = self.client.get('/')
self.assertTemplateUsed(response, 'homepage.html')
def test_homepage_has_title_homepage(self):
new_response = self.client.get('/')
html_response = new_response.content.decode('utf8')
self.assertIn('Homepage', html_response)
def test_homepage_have_my_biography_min_100_char(self):
new_response = self.client.get('/')
html_response = new_response.content.decode('utf8')
self.assertIn('Bio', html_response)
self.assertTrue(len(about_me()) >= 100)
def test_automatic_comment_when_no_items(self):
list_ = List.objects.create()
self.assertEqual(Item.objects.count(), 0)
request = HttpRequest()
response = view_list(request,list_.id)
self.assertIn('yey, waktunya berlibur', response.content.decode())
def test_automatic_comment_when_to_do_have_less_five_items(self):
list_ = List.objects.create()
Item.objects.create(text='Activity 1', list=list_)
Item.objects.create(text='Activity 2', list=list_)
self.assertEqual(Item.objects.count(), 2)
request = HttpRequest()
response = view_list(request,list_.id)
self.assertIn('Activity 1', response.content.decode())
self.assertIn('sibuk tapi santai', response.content.decode())
def test_automatic_comment_when_to_do_have_more_than_or_equal_five_items(self):
list_ = List.objects.create()
Item.objects.create(text='Activity 1', list=list_)
Item.objects.create(text='Activity 2', list=list_)
Item.objects.create(text='Activity 3', list=list_)
Item.objects.create(text='Activity 4', list=list_)
Item.objects.create(text='Activity 5', list=list_)
Item.objects.create(text='Activity 6', list=list_)
self.assertEqual(Item.objects.count(), 6)
request = HttpRequest()
response = view_list(request,list_.id)
self.assertIn('Activity 6', response.content.decode())
self.assertIn('oh tidak', response.content.decode())
class ListViewTest(TestCase):
def test_uses_list_template(self):
......@@ -108,25 +46,4 @@ class ListViewTest(TestCase):
other_list = List.objects.create()
correct_list = List.objects.create()
response = self.client.get('/lists/%d/' % (correct_list.id,))
self.assertEqual(response.context['list'], correct_list)
class NewItemTest(TestCase):
def test_can_save_a_POST_request_to_an_existing_list(self):
other_list = List.objects.create()
correct_list = List.objects.create()
self.client.post(
'/lists/%d/add_item' % (correct_list.id,),
data={'item_text': 'A new item for an existing list'}
)
self.assertEqual(Item.objects.count(), 1)
new_item = Item.objects.first()
self.assertEqual(new_item.text, 'A new item for an existing list')
self.assertEqual(new_item.list, correct_list)
def test_redirects_to_list_view(self):
other_list = List.objects.create()
correct_list = List.objects.create()
response = self.client.post('/lists/%d/add_item' % (correct_list.id,),data={'item_text': 'A new item for an existing list'})
self.assertRedirects(response, '/lists/%d/' % (correct_list.id,))
self.assertEqual(response.context['list'], correct_list)
\ No newline at end of file
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment