Fakultas Ilmu Komputer UI

Commit 31ecdbb4 authored by Muhammad Ilham Peruzzi's avatar Muhammad Ilham Peruzzi
Browse files

Merge branch 'testinggoat/ch12' of...

Merge branch 'testinggoat/ch12' of gitlab.cs.ui.ac.id:pmpl/practice-collection/2019/1606823475-practice
parents 6f768d3c 9d742b52
......@@ -40,4 +40,29 @@ Dengan demikian kita telah berhasil melakukan test isolation.
## 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)
\ No newline at end of file
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.
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
import time
import unittest
import environ
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from unittest import skip
class FunctionalTest(StaticLiveServerTestCase):
def setUp(self):
chrome_options = Options()
chrome_options.add_argument('--dns-prefetch-disable')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--headless')
chrome_options.add_argument('disable-gpu')
try:
self.browser = webdriver.Chrome('./chromedriver.exe', chrome_options=chrome_options)
except:
self.browser = webdriver.Chrome('./chromedriver', chrome_options=chrome_options)
super(FunctionalTest, self).setUp()
def tearDown(self):
self.browser.quit()
def wait_for_row_in_list_table(self, row_text):
MAX_WAIT = 10
start_time = time.time()
while True:
try:
table = self.browser.find_element_by_id('id_list_table')
rows = table.find_elements_by_tag_name('tr')
self.assertIn(row_text, [row.text for row in rows])
return
except (AssertionError, WebDriverException) as e:
if time.time() - start_time > MAX_WAIT:
raise e
time.sleep(0.5)
def wait_for(self, fn):
start_time = time.time()
MAX_WAIT = 10
while True:
try:
return fn()
except (AssertionError, WebDriverException) as e:
if time.time() - start_time > MAX_WAIT:
raise e
time.sleep(0.5)
\ No newline at end of file
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
import time
import unittest
import environ
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from unittest import skip
from .base import FunctionalTest
class LayoutAndStylingTest(FunctionalTest):
def test_layout_and_styling(self):
# Edith goes to the home page
self.browser.get(self.live_server_url)
self.browser.set_window_size(1024, 768)
# She notices the input box is nicely centered
inputbox = self.browser.find_element_by_id('id_new_item')
self.assertAlmostEqual(
inputbox.location['x'] + inputbox.size['width'] / 2,
512,
delta=10
)
#She starts a new list and sees the input is nicely
# centered there too
inputbox.send_keys('testing')
inputbox.send_keys(Keys.ENTER)
self.wait_for_row_in_list_table('1: testing')
inputbox = self.browser.find_element_by_id('id_new_item')
self.assertAlmostEqual(inputbox.location['x'] + inputbox.size['width'] / 2,512,delta=10)
\ No newline at end of file
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.keys import Keys
import time
import unittest
import environ
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from unittest import skip
from .base import FunctionalTest
class ItemValidationTest(FunctionalTest):
def test_cannot_add_empty_list_items(self):
# 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)
# 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"
#))
# 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)
# 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"
#))
# And she can correct it by filling some text in
self.browser.find_element_by_id('id_new_item').send_keys('Make tea')
self.browser.find_element_by_id('id_new_item').send_keys(Keys.ENTER)
self.wait_for_row_in_list_table('1: Buy milk')
self.wait_for_row_in_list_table('2: Make tea')
\ No newline at end of file
......@@ -6,38 +6,10 @@ import time
import unittest
import environ
from django.contrib.staticfiles.testing import StaticLiveServerTestCase
from unittest import skip
from .base import FunctionalTest
class NewVisitorTest(StaticLiveServerTestCase):
MAX_WAIT = 10
def setUp(self):
chrome_options = Options()
chrome_options.add_argument('--dns-prefetch-disable')
chrome_options.add_argument('--no-sandbox')
chrome_options.add_argument('--headless')
chrome_options.add_argument('disable-gpu')
try:
self.browser = webdriver.Chrome('./chromedriver.exe', chrome_options=chrome_options)
except:
self.browser = webdriver.Chrome('./chromedriver', chrome_options=chrome_options)
super(NewVisitorTest, self).setUp()
def tearDown(self):
self.browser.quit()
def wait_for_row_in_list_table(self, row_text):
start_time = time.time()
while True:
try:
table = self.browser.find_element_by_id('id_list_table')
rows = table.find_elements_by_tag_name('tr')
self.assertIn(row_text, [row.text for row in rows])
return
except (AssertionError, WebDriverException) as e:
if time.time() - start_time > MAX_WAIT:
raise e
time.sleep(0.5)
class NewVisitorTest(FunctionalTest):
def test_can_start_a_list_and_retrieve_it_later(self):
self.browser.get(self.live_server_url)
......@@ -90,24 +62,3 @@ class NewVisitorTest(StaticLiveServerTestCase):
self.assertNotIn('Buy peacock feathers', page_text)
self.assertIn('Buy milk', page_text)
# Satisfied, they both go back to sleep
def test_layout_and_styling(self):
# Edith goes to the home page
self.browser.get(self.live_server_url)
self.browser.set_window_size(1024, 768)
# She notices the input box is nicely centered
inputbox = self.browser.find_element_by_id('id_new_item')
self.assertAlmostEqual(
inputbox.location['x'] + inputbox.size['width'] / 2,
512,
delta=10
)
#She starts a new list and sees the input is nicely
# centered there too
inputbox.send_keys('testing')
inputbox.send_keys(Keys.ENTER)
self.wait_for_row_in_list_table('1: testing')
inputbox = self.browser.find_element_by_id('id_new_item')
self.assertAlmostEqual(inputbox.location['x'] + inputbox.size['width'] / 2,512,delta=10)
body .container{padding:10%}body .card-body{background-color:azure}
body {
.container {
padding: 10%;
}
.card-body{
background-color: azure;
}
}
body .container{padding:10%}body .card-body{background-color:azure}
body {
.container {
padding: 10%;
}
.card-body{
background-color: azure;
}
}
{% load sass_tags %}
<html>
<head>
<meta charset="utf-8">
......@@ -6,15 +7,17 @@
<title>To-Do lists</title>
<link href="/static/bootstrap/css/bootstrap.min.css" rel="stylesheet">
<link href="/static/base.css" rel="stylesheet">
<link href="{% sass_src 'scss/list.scss' %}" rel="stylesheet" type="text/css"/>
<link href="{% sass_src 'scss/home.scss' %}" rel="stylesheet" type="text/css"/>
</head>
<body>
<div class="container">
<div class="row">
<div class="col-md-6 col-md-offset-3 jumbotron">
<div class="col-md-6 col-md-offset-3 jumbotron card-body">
<div class="text-center">
<h2>Homepage</h2>
<h2 class="homepage">Homepage</h2>
<hr>
<div id="nama_lengkap">Muhammad Ilham Peruzzi</div>
<h5>Bio</h5>
......
......@@ -6,34 +6,6 @@ from lists.models import Item, List
from lists.views import home_page, about_me, view_list
class ListAndItemModelsTest(TestCase):
def test_saving_and_retrieving_items(self):
list_ = List()
list_.save()
first_item = Item()
first_item.text = 'The first (ever) list item'
first_item.list = list_
first_item.save()
second_item = Item()
second_item.text = 'Item the second'
second_item.list = list_
second_item.save()
saved_list = List.objects.first()
self.assertEqual(saved_list, list_)
saved_items = Item.objects.all()
self.assertEqual(saved_items.count(), 2)
first_saved_item = saved_items[0]
second_saved_item = saved_items[1]
self.assertEqual(first_saved_item.text, 'The first (ever) list item')
self.assertEqual(first_saved_item.list, list_)
self.assertEqual(second_saved_item.text, 'Item the second')
self.assertEqual(second_saved_item.list, list_)
class HomePageTest(TestCase):
def test_root_url_resolves_to_home_page_view(self):
found = resolve('/')
......@@ -42,7 +14,6 @@ class HomePageTest(TestCase):
def test_home_page_returns_correct_html(self):
request = HttpRequest()
response = home_page(request)
self.assertTrue(response.content.startswith(b'<html>'))
self.assertIn(b'<title>To-Do lists</title>', response.content)
self.assertTrue(response.content.strip().endswith(b'</html>'))
......@@ -95,67 +66,4 @@ class HomePageTest(TestCase):
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):
list_ = List.objects.create()
response = self.client.get('/lists/%d/' % (list_.id,))
self.assertTemplateUsed(response, 'list.html')
def test_displays_only_items_for_that_list(self):
correct_list = List.objects.create()
Item.objects.create(text='itemey 1', list=correct_list)
Item.objects.create(text='itemey 2', list=correct_list)
other_list = List.objects.create()
Item.objects.create(text='other list item 1', list=other_list)
Item.objects.create(text='other list item 2', list=other_list)
response = self.client.get('/lists/%d/' % (correct_list.id,))
self.assertContains(response, 'itemey 1')
self.assertContains(response, 'itemey 2')
self.assertNotContains(response, 'other list item 1')
self.assertNotContains(response, 'other list item 2')
def test_displays_all_items(self):
list_ = List.objects.create()
Item.objects.create(text='itemey 1', list=list_)
Item.objects.create(text='itemey 2', list=list_)
def test_saving_a_POST_request(self):
self.client.post('/lists/new',data={'item_text': 'A new list item'})
self.assertEqual(Item.objects.count(), 1)
new_item = Item.objects.first()
self.assertEqual(new_item.text, 'A new list item')
def test_redirects_after_POST(self):
response = self.client.post('/lists/new',data={'item_text': 'A new list item'})
new_list = List.objects.first()
self.assertRedirects(response, '/lists/%d/' % (new_list.id,))
def test_passes_correct_list_to_template(self):
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.assertIn('oh tidak', response.content.decode())
\ No newline at end of file
from django.test import TestCase
from lists.models import Item, List
class ListAndItemModelsTest(TestCase):
def test_saving_and_retrieving_items(self):
list_ = List()
list_.save()
first_item = Item()
first_item.text = 'The first (ever) list item'
first_item.list = list_
first_item.save()
second_item = Item()
second_item.text = 'Item the second'
second_item.list = list_
second_item.save()
saved_list = List.objects.first()
self.assertEqual(saved_list, list_)
saved_items = Item.objects.all()
self.assertEqual(saved_items.count(), 2)
first_saved_item = saved_items[0]
second_saved_item = saved_items[1]
self.assertEqual(first_saved_item.text, 'The first (ever) list item')
self.assertEqual(first_saved_item.list, list_)
self.assertEqual(second_saved_item.text, 'Item the second')
self.assertEqual(second_saved_item.list, list_)
\ 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
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 ListViewTest(TestCase):
def test_uses_list_template(self):
list_ = List.objects.create()
response = self.client.get('/lists/%d/' % (list_.id,))
self.assertTemplateUsed(response, 'list.html')
def test_displays_only_items_for_that_list(self):
correct_list = List.objects.create()
Item.objects.create(text='itemey 1', list=correct_list)
Item.objects.create(text='itemey 2', list=correct_list)
other_list = List.objects.create()
Item.objects.create(text='other list item 1', list=other_list)
Item.objects.create(text='other list item 2', list=other_list)
response = self.client.get('/lists/%d/' % (correct_list.id,))
self.assertContains(response, 'itemey 1')
self.assertContains(response, 'itemey 2')
self.assertNotContains(response, 'other list item 1')
self.assertNotContains(response, 'other list item 2')
def test_displays_all_items(self):
list_ = List.objects.create()
Item.objects.create(text='itemey 1', list=list_)
Item.objects.create(text='itemey 2', list=list_)
def test_saving_a_POST_request(self):
self.client.post('/lists/new',data={'item_text': 'A new list item'})
self.assertEqual(Item.objects.count(), 1)
new_item = Item.objects.first()
self.assertEqual(new_item.text, 'A new list item')
def test_redirects_after_POST(self):
response = self.client.post('/lists/new',data={'item_text': 'A new list item'})
new_list = List.objects.first()
self.assertRedirects(response, '/lists/%d/' % (new_list.id,))
def test_passes_correct_list_to_template(self):
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)
\ No newline at end of file
......@@ -41,7 +41,8 @@ INSTALLED_APPS = [
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'lists'
'lists',
'sass_processor'
]
MIDDLEWARE = [
......@@ -135,3 +136,10 @@ USE_TZ = True
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(PROJECT_DIR, 'static')
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
SASS_PROCESSOR_ROOT = os.path.join(PROJECT_DIR, 'static')
STATICFILES_FINDERS = [
'django.contrib.staticfiles.finders.FileSystemFinder',
'django.contrib.staticfiles.finders.AppDirectoriesFinder',
'sass_processor.finders.CssFinder',
]
\ No newline at end of file
#id_new_item {
margin-top: 2ex;
}
\ No newline at end of file
#id_new_item {
margin-top: 2ex;
}
\ No newline at end of file
#id_new_item {
margin-top: 2ex;
}
\ 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