diff --git a/README.md b/README.md index ee58f77be4aea278e1d502e625ae0c848149978b..70feba0524c525246ff951fd016be239613a5be5 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,17 @@ # 1606821886-practice Herokuapp : https://pmpl-farah.herokuapp.com/ +## Table of Contents + + - Exercise 3 : + - Proses test isolation + - Perbedaan pada design + - Exercise 4 : + - Keterhubungan Chapter 8 dan 7 + - Exercise 5 : + - Keterkaitan refactoring dan clean code + - Keuntungan test organization. + ## Exercise 3 **Proses test isolation** @@ -48,4 +59,17 @@ def test_can_start_a_list_and_retrieve_it_later(self): **Keterhubungan Chapter 8 dan 7** Pada bab 7, saya melakukan perubahan pada struktur kode yang memungkinkan ada lebih dari satu user yang bisa memulai sebuah To-Do List. Sehingga saya mengimplementasikan URL yang unik untuk setiap list, seperti petunjuk di buku. -Pada bab 8, saya memperbaiki tampilan halaman dengan menggunakan css dan Bootstrap. Dari html yang sudah dibuat pada bab 7, saya mengimplementasikan django template inheritance dengan membuat satu html sebagai "superclass" yaitu base.html. \ No newline at end of file +Pada bab 8, saya memperbaiki tampilan halaman dengan menggunakan css dan Bootstrap. Dari html yang sudah dibuat pada bab 7, saya mengimplementasikan django template inheritance dengan membuat satu html sebagai "superclass" yaitu base.html. + +## Exercise 5 +**Keterkaitan refactoring dan konsep clean code** +Tujuan utama dilakukannya refactoring adalah untuk mencapai atau memelihara clean code. Dengan Red Green Refactor, kita dapat : + - Menghindari duplication + - Meningkatkan code coverage + - Memudahkan maintenance + +Dengan menerapkan Red Green Refactor, berarti kita juga menerapkan konsep clean code. + +**Keuntungan test organization** +Memudahkan maintenance. Kita dapat dengan mudah menemukan test code yang kita butuhkan karena test sudah teratur dalam kategori-kategori. + diff --git a/functional_tests/base.py b/functional_tests/base.py new file mode 100644 index 0000000000000000000000000000000000000000..2550a0dfb2a9ee18de60424756255d1dfa452c91 --- /dev/null +++ b/functional_tests/base.py @@ -0,0 +1,47 @@ +from selenium.common.exceptions import WebDriverException +from django.contrib.staticfiles.testing import StaticLiveServerTestCase +from selenium import webdriver +from selenium.webdriver.firefox.options import Options +import time +import environ + +MAX_WAIT = 10 + +class FunctionalTest(StaticLiveServerTestCase): + + def setUp(self): + options = Options() + options.headless = True + self.browser = webdriver.Firefox(options=options) + self.browser.implicitly_wait(5) + + 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) + + def check_for_row_in_list_table(self, row_text): + 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]) + + def wait_for(self, fn): + start_time = time.time() + 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 diff --git a/functional_tests/test_layout_and_styling.py b/functional_tests/test_layout_and_styling.py new file mode 100644 index 0000000000000000000000000000000000000000..97c06d5550de9651a53d9d20deb1956fadaeaf17 --- /dev/null +++ b/functional_tests/test_layout_and_styling.py @@ -0,0 +1,28 @@ +from .base import FunctionalTest +from selenium.webdriver.common.keys import Keys + +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 diff --git a/functional_tests/test_list_item_validation.py b/functional_tests/test_list_item_validation.py new file mode 100644 index 0000000000000000000000000000000000000000..2215c18b03c8a2242006b13fb764a7fc4987fa52 --- /dev/null +++ b/functional_tests/test_list_item_validation.py @@ -0,0 +1,42 @@ +from .base import FunctionalTest +from selenium.webdriver.common.keys import Keys +from unittest import skip + +class ItemValidationTest(FunctionalTest): + + @skip + 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) + 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') + + # 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') + +#if __name__ == '__main__': +# unittest.main(warnings='ignore') diff --git a/functional_tests/tests.py b/functional_tests/test_simple_list_creation.py similarity index 65% rename from functional_tests/tests.py rename to functional_tests/test_simple_list_creation.py index 32719c01a959c96f939843d56ac463df839e91c3..dfe370653572e2ddef4ea2809f864ebc3a80e855 100644 --- a/functional_tests/tests.py +++ b/functional_tests/test_simple_list_creation.py @@ -1,29 +1,11 @@ -from selenium.common.exceptions import WebDriverException -from django.contrib.staticfiles.testing import StaticLiveServerTestCase +from .base import FunctionalTest from selenium import webdriver from selenium.webdriver.common.keys import Keys from selenium.webdriver.firefox.options import Options -import time -import unittest -import environ -MAX_WAIT = 10 -class NewVisitorTest(StaticLiveServerTestCase): - def setUp(self): - options = Options() - options.headless = True - self.browser = webdriver.Firefox(options=options) - self.browser.implicitly_wait(5) - - def tearDown(self): - self.browser.quit() - - def check_for_row_in_list_table(self, row_text): - 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]) +class NewVisitorTest(FunctionalTest): def test_can_start_a_list_for_one_user(self) : # Edith has heard about a cool new online to-do app. She goes @@ -73,19 +55,6 @@ class NewVisitorTest(StaticLiveServerTestCase): # She visits that URL - her to-do list is still there. # Satisfied, she goes back to sleep - 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) - def test_multiple_users_can_start_lists_at_different_urls(self): # Edith starts a new to-do list self.browser.get(self.live_server_url) @@ -131,31 +100,4 @@ 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 - ) - -#if __name__ == '__main__': -# unittest.main(warnings='ignore') + # Satisfied, they both go back to sleep \ No newline at end of file diff --git a/lists/tests/__init__.py b/lists/tests/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/lists/tests/test_models.py b/lists/tests/test_models.py new file mode 100644 index 0000000000000000000000000000000000000000..75cca5d65e63144b05d5e6ce16a3da66bbb2362c --- /dev/null +++ b/lists/tests/test_models.py @@ -0,0 +1,32 @@ +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 diff --git a/lists/tests.py b/lists/tests/test_views.py similarity index 83% rename from lists/tests.py rename to lists/tests/test_views.py index 14daa5edd15967d1df80e886b71ff9037a3a81fd..0225175d0eda82f1e72008d52428133b593e2cf1 100644 --- a/lists/tests.py +++ b/lists/tests/test_views.py @@ -127,33 +127,4 @@ class HomePageTest(TestCase): response = self.client.get(f'/lists/{list_.id}/') self.assertIn('Oh tidak', response.content.decode()) -class ItemModelTest(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_) -