วันอาทิตย์ที่ 15 มิถุนายน พ.ศ. 2557

Chapter 5. Saving User Input

Chapter 5. Saving User Input


Wiring Up Our Form to Send a POST Request

แก้ไขไฟล์ lists/templates/home.html. 

<h1>Your To-Do list</h1>
        <form method="POST">
     <input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
 </form>

 <table id="id_list_table">

รันไฟล์ Functional_test.py จะแสดงผลดังนี้ คือ โปรแกรม Error และไม่สามารถหาองค์ประกอบของ method : id , selector : id_list_table
$ python functional_tests.py 
E
======================================================================
ERROR: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 39, in test_can_start_a_list_and_retrieve_it_later
    table = self.browser.find_element_by_id('id_list_table')
  File "/usr/local/lib/python2.7/dist-packages/selenium-2.41.0-py2.7.egg/selenium/webdriver/remote/webdriver.py", line 199, in find_element_by_id
    return self.find_element(by=By.ID, value=id_)
  File "/usr/local/lib/python2.7/dist-packages/selenium-2.41.0-py2.7.egg/selenium/webdriver/remote/webdriver.py", line 655, in find_element
    {'using': by, 'value': value})['value']
  File "/usr/local/lib/python2.7/dist-packages/selenium-2.41.0-py2.7.egg/selenium/webdriver/remote/webdriver.py", line 166, in execute
    self.error_handler.check_response(response)
  File "/usr/local/lib/python2.7/dist-packages/selenium-2.41.0-py2.7.egg/selenium/webdriver/remote/errorhandler.py", line 164, in check_response
    raise exception_class(message, screen, stacktrace)
NoSuchElementException: Message: u'Unable to locate element: {"method":"id","selector":"id_list_table"}' ; Stacktrace: 
    at FirefoxDriver.prototype.findElementInternal_ (file:///tmp/tmpVZoONB/extensions/fxdriver@googlecode.com/components/driver_component.js:8905)
    at fxdriver.Timer.prototype.setTimeout/<.notify (file:///tmp/tmpVZoONB/extensions/fxdriver@googlecode.com/components/driver_component.js:396) 

----------------------------------------------------------------------
Ran 1 test in 17.221s

FAILED (errors=1)

แก้ไขไฟล์ functional_tests.py.

    # When she hits enter, the page updates, and now the page lists
    # "1: Buy peacock feathers" as an item in a to-do list table
    inputbox.send_keys(Keys.ENTER)

    import time
    time.sleep(10)
    table = self.browser.find_element_by_id('id_list_table')

ทำการรันไฟล์ functional_test.py จะทำให้เกิด Error ดังนี้ คือ page จะแสดง CSRF Error

แก้ไขไฟล์ lists/templates/home.html เพื่อไม่ให้เกิด CSRF Error


<form method="POST">
    <input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
    {% csrf_token %}
</form>

เมื่อทำการรันไฟล์ functional_test.py จะแสดง browser ขึ้นมา ทำให้เห็นว่าในช่องข้อความนั้นว่างเปล่า

และแสดงผลดังนี้ คือ ไม่พบรายการใหม่ในตาราง
$ python functional_tests.py 
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 46, in test_can_start_a_list_and_retrieve_it_later
    "New to-do item did not appear in table"
AssertionError: New to-do item did not appear in table

----------------------------------------------------------------------
Ran 1 test in 26.127s

FAILED (failures=1)

แก้ไขไฟล์ functional_tests.py.  โดยทำการลบ time.sleep ออก
    # "1: Buy peacock feathers" as an item in a to-do list table
    inputbox.send_keys(Keys.ENTER)

    table = self.browser.find_element_by_id('id_list_table')

Processing a POST Request on the Server

จะเพิ่ม unit test อันใหม่สำหรับ home_page
แก้ไขไฟล์ lists/tests.py โดยจะแอด method เพิ่มเข้าไป ซึ่งก่อนหน้านี้ทำการปรับให้เพิ่มคำขอ POST และตรวจสอบการ return ของ HTML ว่าจะมีข้อความใหม่

def test_home_page_returns_correct_html(self):
    [...]


def test_home_page_can_save_a_POST_request(self):
    request = HttpRequest()
    request.method = 'POST'
    request.POST['item_text'] = 'A new list item'

    response = home_page(request)

    self.assertIn('A new list item', response.content.decode())

ทำการรันไฟล์ test.py จะแสดงผลดังนี้คือ ไม่พบ A new list item
$ python manage.py test
Creating test database for alias 'default'...
F..
======================================================================
FAIL: test_home_page_can_save_a_POST_request (lists.tests.HomePageTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jutamas/Desktop/summer/superlists/lists/tests.py", line 37, in test_home_page_can_save_a_POST_request
    self.assertIn('A new list item', response.content.decode())
AssertionError: 'A new list item' not found in u'<html>\n    <head>\n        <title>To-Do lists</title>\n    </head>\n    <body>\n        <h1>Your To-Do list</h1>\n        <form method="POST">\n    \t<input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />\n    \t\n\t</form>\n\n\t<table id="id_list_table">\n    </table>\n    </body>\n</html>\n'

----------------------------------------------------------------------
Ran 3 tests in 0.013s

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

เราจะทำการทดสอบให้ผ่านโดยการเพิ่มและให้ code path ที่แตกต่างกันสำหรับ POST request ในรูปแบบของ TDD เราจะเริ่มต้นด้วยการ return ค่า
แก้ไขไฟล์ lists/views.py

from django.http import HttpResponse
from django.shortcuts import render

def home_page(request):
    if request.method == 'POST':
        return HttpResponse(request.POST['item_text'])
    return render(request, 'home.html')

ทำการรันไฟล์ test.py จะแสดงผลการรันผ่านสำเร็จ
$ python manage.py test
Creating test database for alias 'default'...
...
----------------------------------------------------------------------
Ran 3 tests in 0.005s

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

Passing Python Variables to Be Rendered in the Template

แก้ไขไฟล์ lists/templates/home.html เพื่อแสดง objects  เป็นสตริง
<body>
    <h1>Your To-Do list</h1>
    <form method="POST">
        <input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />
        {% csrf_token %}
    </form>

    <table id="id_list_table">
        <tr><td>{{ new_item_text }}</td></tr>
    </table>
</body>

แก้ไขไฟล์ lists/tests.py. ซึ่งจะทำการ render เป็นสตริง และทำการเปรียบเทียบกับ new item

self.assertIn('A new list item', response.content.decode())
    expected_html = render_to_string(
        'home.html',
        {'new_item_text':  'A new list item'}
    )
    self.assertEqual(response.content.decode(), expected_html)

ทำการรันไฟล์ test.py จะแสดงผล Error ดังนี้

$ python manage.py test
Creating test database for alias 'default'...
F..
======================================================================
FAIL: test_home_page_can_save_a_POST_request (lists.tests.HomePageTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jutamas/Desktop/summer/superlists/lists/tests.py", line 42, in test_home_page_can_save_a_POST_request
    self.assertEqual(response.content.decode(), expected_html)
AssertionError: u'A new list item' != u'<html>\n    <head>\n        <title>To-Do lists</title>\n    </head>\n    <body>\n    <h1>Your To-Do list</h1>\n    <form method="POST">\n        <input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />\n        \n    </form>\n\n    <table id="id_list_table">\n        <tr><td>A new list item</td></tr>\n    </table>\n    </body>\n</html>\n'

----------------------------------------------------------------------
Ran 3 tests in 0.006s

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

แก้ไขไฟล์ lists/views.py 

def home_page(request):
    return render(request, 'home.html', {
        'new_item_text': request.POST['item_text'],
    })

รันไฟล์ test.py จะแสดง error ดังนี้คือ key error ที่ item_text

$ python manage.py test
Creating test database for alias 'default'...
.E.
======================================================================
ERROR: test_home_page_returns_correct_html (lists.tests.HomePageTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jutamas/Desktop/summer/superlists/lists/tests.py", line 25, in test_home_page_returns_correct_html
    response = home_page(request)
  File "/home/jutamas/Desktop/summer/superlists/lists/views.py", line 6, in home_page
    'new_item_text': request.POST['item_text'],
KeyError: 'item_text'

----------------------------------------------------------------------
Ran 3 tests in 0.005s

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

แก้ไขไฟล์ lists/views.py เพื่อให้สามารถรันผ่าน

def home_page(request):
    return render(request, 'home.html', {
        'new_item_text': request.POST.get('item_text', ''),
    })

ทำการรันไฟล์ test.py จะแสดงผลดังนี้ คือสามารถผ่าน
$ python manage.py test
Creating test database for alias 'default'...
...
----------------------------------------------------------------------
Ran 3 tests in 0.007s

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

และทำการรันไฟล์ functional_test.py จะแสดงผลดังนี้คือ ไม่พบ New to-do item ไม่ปรากฏในตาราง

$ python functional_tests.py 
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 44, in test_can_start_a_list_and_retrieve_it_later
    "New to-do item did not appear in table"
AssertionError: New to-do item did not appear in table

----------------------------------------------------------------------
Ran 1 test in 5.958s

FAILED (failures=1)

เราจะใช้ functional test เป็นเทคนิคการแก้ไขข้อผิดพลาด นี่อาจเป็นเทคนิคที่สร้างสรรค์ เพราะ การปรับปรุงข้อผิดพลาดจะอยู่รอบๆข้อความความ error และจะทำให้แก้ไขข้อผิดพลาดในอนาคตได้ 
แก้ไขไฟล์ functional_tests.py.

self.assertTrue(
        any(row.text == '1: Buy peacock feathers' for row in rows),
        "New to-do item did not appear in table -- its text was:\n%s" % (
            table.text,
        )
    )

รันไฟล์ test.py จะแสดงผลดังนี้ คือ New to-do item ไม่พบในตาราง ข้อความจะเป็น Buy peacock feathers
$ python functional_tests.py 
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 45, in test_can_start_a_list_and_retrieve_it_later
    table.text,
AssertionError: New to-do item did not appear in table -- its text was:
Buy peacock feathers

----------------------------------------------------------------------
Ran 1 test in 6.133s

FAILED (failures=1)

ทำการแก้ไขไฟล์ functional_tests.py.


    self.assertIn('1: Buy peacock feathers', [row.text for row in rows])

รันไฟล์ functional_test.py จะแสดงผลดังนี้

$ python functional_tests.py 
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 42, in test_can_start_a_list_and_retrieve_it_later
    self.assertIn('1: Buy peacock feathers', [row.text for row in rows])
AssertionError: '1: Buy peacock feathers' not found in [u'Buy peacock feathers']

----------------------------------------------------------------------
Ran 1 test in 6.205s

FAILED (failures=1)

ทำการแก้ไขไฟล์ lists/templates/home.html. โดยใส่ข้อมูลเข้าไปในตาราง


<tr><td>1: {{ new_item_text }}</td></tr>

ทำการรันไฟล์ functional_test.py จะแสดงผลดังนี้ คือจะรันผ่าน
$ python functional_tests.py 
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 47, in test_can_start_a_list_and_retrieve_it_later
    self.fail('Finish the test!')
AssertionError: Finish the test!

----------------------------------------------------------------------
Ran 1 test in 6.026s

FAILED (failures=1)

ถ้าเราต้องการตรวจสอบรายการลำดับที่ 2 ในตาราง
ทำการแก้ไขไฟล์ functional_tests.py 
    # There is still a text box inviting her to add another item. She
    # enters "Use peacock feathers to make a fly" (Edith is very
    # methodical)
    inputbox = self.browser.find_element_by_id('id_new_item')
    inputbox.send_keys('Use peacock feathers to make a fly')
    inputbox.send_keys(Keys.ENTER)

    # The page updates again, and now shows both items on her list
    table = self.browser.find_element_by_id('id_list_table')
    rows = table.find_elements_by_tag_name('tr')
    self.assertIn('1: Buy peacock feathers', [row.text for row in rows])
    self.assertIn(
        '2: Use peacock feathers to make a fly' ,
         [row.text for row in rows]
    )

    # Edith wonders whether the site will remember her list. Then she sees
    # that the site has generated a unique URL for her -- there is some
    # explanatory text to that effect.
    self.fail('Finish the test!')

    # She visits that URL - her to-do list is still there.

รันไฟล์ functional_test.py จะแสดงผลดังนี้
$ python functional_tests.py 
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 55, in test_can_start_a_list_and_retrieve_it_later
    self.assertIn('1: Buy peacock feathers', [row.text for row in rows])
AssertionError: '1: Buy peacock feathers' not found in [u'1: Use peacock feathers to make a fly']

----------------------------------------------------------------------
Ran 1 test in 6.297s

FAILED (failures=1)

Three Strikes and Refactor

คำสั่ง git diff ดูการแก้ไขไฟล์
$ git diff
diff --git a/functional_tests.py b/functional_tests.py
index 5487abb..94ed2a3 100644
--- a/functional_tests.py
+++ b/functional_tests.py
@@ -36,19 +36,35 @@ class NewVisitorTest(unittest.TestCase):  #1
         # "1: Buy peacock feathers" as an item in a to-do list table
         inputbox.send_keys(Keys.ENTER)
 
-        table = self.browser.find_element_by_id('id_list_table')
+       table = self.browser.find_element_by_id('id_list_table')
         rows = table.find_elements_by_tag_name('tr')
         
-       self.assertTrue(
-            any(row.text == '1: Buy peacock feathers' for row in rows),
-           "New to-do item did not appear in table"
-       )
+       self.assertIn('1: Buy peacock feathers', [row.text for row in rows])
 
         # There is still a text box inviting her to add another item. She
         # enters "Use peacock feathers to make a fly" (Edith is very
         # methodical)
-        self.fail('Finish the test!')
 
:

คำสั่ง git commit เพื่อคอมมิทการแก้ไขไฟล์

$ git commit -a
[master 0cc6302] Test home page can save a POST request
 Committer: jutamas <jutamas@jutamas.(none)>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 8 files changed, 110 insertions(+), 22 deletions(-)

กลับมาที่ functional test เราจะเพิ่ม method เข้าไปเพื่อช่วยในการจดจำ
แก้ไขไฟล์ functional_tests.py.


    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])


    def test_can_start_a_list_and_retrieve_it_later(self):
        [...]

แก้ไขไฟล์ functional_test.py

    # When she hits enter, the page updates, and now the page lists
    # "1: Buy peacock feathers" as an item in a to-do list table
    inputbox.send_keys(Keys.ENTER)
    self.check_for_row_in_list_table('1: Buy peacock feathers')

    # There is still a text box inviting her to add another item. She
    # enters "Use peacock feathers to make a fly" (Edith is very
    # methodical)
    inputbox = self.browser.find_element_by_id('id_new_item')
    inputbox.send_keys('Use peacock feathers to make a fly')
    inputbox.send_keys(Keys.ENTER)

    # The page updates again, and now shows both items on her list
    self.check_for_row_in_list_table('1: Buy peacock feathers')
    self.check_for_row_in_list_table('2: Use peacock feathers to make a fly')

    # Edith wonders whether the site will remember her list. Then she sees
    [...]

รันไฟล์ functional_test.py จะแสดงผลดังนี้

$ python functional_tests.py 
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 53, in test_can_start_a_list_and_retrieve_it_later
    self.check_for_row_in_list_table('1: Buy peacock feathers')
  File "functional_tests.py", line 17, in check_for_row_in_list_table
    self.assertIn(row_text, [row.text for row in rows])
AssertionError: '1: Buy peacock feathers' not found in [u'1: Use peacock feathers to make a fly']

----------------------------------------------------------------------
Ran 1 test in 6.404s

FAILED (failures=1)

คำสั่ง git diff เพื่อดูการแก้ไขไฟล์

$ git diff
diff --git a/functional_tests.py b/functional_tests.py
index 94ed2a3..d2643be 100644
--- a/functional_tests.py
+++ b/functional_tests.py
@@ -10,6 +10,11 @@ class NewVisitorTest(unittest.TestCase):  #1
 
     def tearDown(self):  #3
         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])
        
     def test_can_start_a_list_and_retrieve_it_later(self):  #4
         # Edith has heard about a cool new online to-do app. She goes
@@ -33,30 +38,20 @@ class NewVisitorTest(unittest.TestCase):  #1
         inputbox.send_keys('Buy peacock feathers')
 
         # When she hits enter, the page updates, and now the page lists
-        # "1: Buy peacock feathers" as an item in a to-do list table
-        inputbox.send_keys(Keys.ENTER)
-
:

คำสั่ง git commit คอมมิทการแก้ไขไฟล์

$ git commit -a
[master 05d06bb] Three Strikes and Refactor
 Committer: jutamas <jutamas@jutamas.(none)>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:

    git config --global user.name "Your Name"
    git config --global user.email you@example.com

After doing this, you may fix the identity used for this commit with:

    git commit --amend --reset-author

 2 files changed, 19 insertions(+), 19 deletions(-)

The Django ORM and Our First Model

แก้ไขไฟล์ lists/tests.py. 
 
from lists.models import Item
[...]

class ItemModelTest(TestCase):

    def test_saving_and_retrieving_items(self):
        first_item = Item()
        first_item.text = 'The first (ever) list item'
        first_item.save()

        second_item = Item()
        second_item.text = 'Item the second'
        second_item.save()

        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(second_saved_item.text, 'Item the second')

ทำการรันไฟล์ test.py จะแสดงผลดังนี้ คือ ไม่สามารถ import ชื่อ item ได้

$ python manage.py test
Creating test database for alias 'default'...
E
======================================================================
ERROR: lists.tests (unittest.loader.ModuleImportFailure)
----------------------------------------------------------------------
ImportError: Failed to import test module: lists.tests
Traceback (most recent call last):
  File "/usr/lib/python2.7/unittest/loader.py", line 252, in _find_tests
    module = self._get_module_from_name(name)
  File "/usr/lib/python2.7/unittest/loader.py", line 230, in _get_module_from_name
    __import__(name)
  File "/home/jutamas/Desktop/summer/superlists/lists/tests.py", line 6, in <module>
    from lists.models import Item
ImportError: cannot import name Item


----------------------------------------------------------------------
Ran 1 test in 0.000s

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

แก้ไขไฟล์ lists/models.py. 

from django.db import models

class Item(object):
    pass

ทำการรันไฟล์ test.py จะแสดงผลดังนี้ คือ Item ไม่มี attribute 'save'

$ python manage.py test
Creating test database for alias 'default'...
...E
======================================================================
ERROR: test_saving_and_retrieving_items (lists.tests.ItemModelTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jutamas/Desktop/summer/superlists/lists/tests.py", line 50, in test_saving_and_retrieving_items
    first_item.save()
AttributeError: 'Item' object has no attribute 'save'

----------------------------------------------------------------------
Ran 4 tests in 0.007s

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

แก้ไขไฟล์ lists/models.py. 

from django.db import models

class Item(models.Model):
    pass

ทำการรันไฟล์ test lists จะแสดงผลดังนี้ คือ Item ไม่มี attribute 'text'

$ python manage.py test lists
Creating test database for alias 'default'...
...E
======================================================================
ERROR: test_saving_and_retrieving_items (lists.tests.ItemModelTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jutamas/Desktop/summer/superlists/lists/tests.py", line 61, in test_saving_and_retrieving_items
    self.assertEqual(first_saved_item.text, 'The first (ever) list item')
AttributeError: 'Item' object has no attribute 'text'

----------------------------------------------------------------------
Ran 4 tests in 0.008s

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

แก้ไขไฟล์ lists/models.py.

class Item(models.Model):
    text = models.TextField()

ทำการรันไฟล์ test lists จะแสดงผลดังนี้ คือ รันผ่าน

$ python manage.py test lists
Creating test database for alias 'default'...
....
----------------------------------------------------------------------
Ran 4 tests in 0.010s

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

ทำการเช็คสถานะไฟล์ แอด lists และ คอมมิทโดยใช้ชื่อ Model for list Items and associated migration

$ git status
$ git diff
$ git add lists
$ git commit -m"Model for list Items and associated migration"

Saving the POST to the Database
แก้ไขไฟล์ lists/tests.py. โดยเพิ่มฟังก์ชั่น test_home_page_can_save_a_POST_request(selft) เพื่อทดสอบว่าสามารถคำร้องขอได้หรือไม่
 
def test_home_page_can_save_a_POST_request(self):
    request = HttpRequest()
    request.method = 'POST'
    request.POST['item_text'] = 'A new list item'

    response = home_page(request)

    self.assertEqual(Item.objects.count(), 1)  #1
    new_item = Item.objects.first()  #2
    self.assertEqual(new_item.text, 'A new list item')  #3

    self.assertIn('A new list item', response.content.decode())
    expected_html = render_to_string(
        'home.html',
        {'new_item_text':  'A new list item'}
    )
    self.assertEqual(response.content.decode(), expected_html)

ทำการรันไฟล์ test จะแสดงผลดังนี้ คือ 0 != 1

$ python manage.py test
Creating test database for alias 'default'...
F...
======================================================================
FAIL: test_home_page_can_save_a_POST_request (lists.tests.HomePageTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jutamas/Desktop/summer/superlists/lists/tests.py", line 38, in test_home_page_can_save_a_POST_request
    self.assertEqual(Item.objects.count(), 1)  #1
AssertionError: 0 != 1

----------------------------------------------------------------------
Ran 4 tests in 0.009s

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

แก้ไขไฟล์ lists/views.py. 

from django.shortcuts import render
from lists.models import Item

def home_page(request):
    item = Item()
    item.text = request.POST.get('item_text', '')
    item.save()

    return render(request, 'home.html', {
        'new_item_text': request.POST.get('item_text', ''),
    })

ทำการรันไฟล์ test จะแสดงผลดังนี้คือ สามารถรันผ่าน

$ python manage.py test
Creating test database for alias 'default'...
....
----------------------------------------------------------------------
Ran 4 tests in 0.010s

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

แก้ไขไฟล์ lists/views.py.

    return render(request, 'home.html', {
        'new_item_text': item.text
    })

ทำการรันไฟล์ test จะแสดงผลดังนี้ คือ รันผ่าน

$ python manage.py test
Creating test database for alias 'default'...
....
----------------------------------------------------------------------
Ran 4 tests in 0.010s

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

แก้ไขไฟล์ lists/tests.py. ในคลาส HomePageTest เพิ่มฟังก์ชั่น test_home_page_only_saves_item_when_necessary(self):

class HomePageTest(TestCase):
    [...]

    def test_home_page_only_saves_items_when_necessary(self):
        request = HttpRequest()
        home_page(request)
        self.assertEqual(Item.objects.count(), 0)

ทำการรันไฟล์ test จะแสดงผลดังนี้ คือ 1 != 0

$ python manage.py test
Creating test database for alias 'default'...
.F...
======================================================================
FAIL: test_home_page_only_saves_items_when_necessary (lists.tests.HomePageTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jutamas/Desktop/summer/superlists/lists/tests.py", line 52, in test_home_page_only_saves_items_when_necessary
    self.assertEqual(Item.objects.count(), 0)
AssertionError: 1 != 0

----------------------------------------------------------------------
Ran 5 tests in 0.011s

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

แก้ไขไฟล์ lists/views.py.
def home_page(request):
    if request.method == 'POST':
        new_item_text = request.POST['item_text']  #1
        Item.objects.create(text=new_item_text)  #2
    else:
        new_item_text = ''  #3

    return render(request, 'home.html', {
        'new_item_text': new_item_text,  #4
    })

ทำการรันไฟล์ test จะแสดงผลดังนี้ คือ สามารถรันผ่าน

$ python manage.py test
Creating test database for alias 'default'...
.....
----------------------------------------------------------------------
Ran 5 tests in 0.012s

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

Redirect After a POST
แก้ไขไฟล์ lists/tests.py 


def test_home_page_can_save_a_POST_request(self):
        request = HttpRequest()
        request.method = 'POST'
        request.POST['item_text'] = 'A new list item'

        response = home_page(request)

        self.assertEqual(Item.objects.count(), 1)
        new_item = Item.objects.first()
        self.assertEqual(new_item.text, 'A new list item')

        self.assertEqual(response.status_code, 302)
        self.assertEqual(response['location'], '/')

ทำการรันไฟล์ test จะแสดงผลดังนี้ คือ 200 != 302

$ python manage.py test
Creating test database for alias 'default'...
F....
======================================================================
FAIL: test_home_page_can_save_a_POST_request (lists.tests.HomePageTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jutamas/Desktop/summer/superlists/lists/tests.py", line 42, in test_home_page_can_save_a_POST_request
    self.assertEqual(response.status_code, 302)
AssertionError: 200 != 302

----------------------------------------------------------------------
Ran 5 tests in 0.010s

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

แก้ไขไฟล์ lists/views.py

from django.shortcuts import redirect, render
from lists.models import Item

def home_page(request):
    if request.method == 'POST':
        Item.objects.create(text=request.POST['item_text'])
        return redirect('/')

    return render(request, 'home.html')

ทำการรันไฟล์ test จะแสดงผลดังนี้ คือ รันผ่าน

$ python manage.py test
Creating test database for alias 'default'...
.....
----------------------------------------------------------------------
Ran 5 tests in 0.012s

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

Better Unit Testing Practice: Each Test Should Test One Thing
แก้ไขไฟล์ lists/tests.py. 

def test_home_page_can_save_a_POST_request(self):
        request = HttpRequest()
        request.method = 'POST'
        request.POST['item_text'] = 'A new list item'

        response = home_page(request)

        self.assertEqual(Item.objects.count(), 1)
        new_item = Item.objects.first()
        self.assertEqual(new_item.text, 'A new list item')


    def test_home_page_redirects_after_POST(self):
        request = HttpRequest()
        request.method = 'POST'
        request.POST['item_text'] = 'A new list item'

        response = home_page(request)

        self.assertEqual(response.status_code, 302)
        self.assertEqual(response['location'], '/')

ทำการรันไฟล์ test จะแสดงผลดังนี้คือ รันผ่าน

$ python manage.py test
Creating test database for alias 'default'...
......
----------------------------------------------------------------------
Ran 6 tests in 0.011s

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

Rendering Items in the Template
การแสดงรายการใน template
แก้ไขไฟล์ lists/tests.py
 
class HomePageTest(TestCase):
    [...]

    def test_home_page_displays_all_list_items(self):
        Item.objects.create(text='itemey 1')
        Item.objects.create(text='itemey 2')

        request = HttpRequest()
        response = home_page(request)

        self.assertIn('itemey 1', response.content.decode())
        self.assertIn('itemey 2', response.content.decode())

ทำการรันไฟล์ test จะแสดงผลดังนี้ คือ 'itemey 1' ไม่พบใน '<html>\n [...]
$ python manage.py test
Creating test database for alias 'default'...
.F.....
======================================================================
FAIL: test_home_page_displays_all_list_items (lists.tests.HomePageTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jutamas/Desktop/summer/superlists/lists/tests.py", line 65, in test_home_page_displays_all_list_items
    self.assertIn('itemey 1', response.content.decode())
AssertionError: 'itemey 1' not found in u'<html>\n    <head>\n        <title>To-Do lists</title>\n    </head>\n    <body>\n    <h1>Your To-Do list</h1>\n    <form method="POST">\n        <input name="item_text" id="id_new_item" placeholder="Enter a to-do item" />\n        \n    </form>\n\n    <table id="id_list_table">\n        <tr><td>1: </td></tr>\n    </table>\n    </body>\n</html>\n'

----------------------------------------------------------------------
Ran 7 tests in 0.012s

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

แก้ไขไฟล์ lists/templates/home.html.

<table id="id_list_table">
    {% for item in items %}
        <tr><td>1: {{ item.text }}</td></tr>
    {% endfor %}
</table>

แก้ไขไฟล์ lists/views.py.

def home_page(request):
    if request.method == 'POST':
        Item.objects.create(text=request.POST['item_text'])
        return redirect('/')

    items = Item.objects.all()
    return render(request, 'home.html', {'items': items})

เมื่อทำการรันไฟล์ functional_test แล้วจะมีหน้าบราวเซอร์ เด้งขึ้นมาดังรูป

และในโปรแกรมจะ Error ดังนี้

$ python functional_tests.py 
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 25, in test_can_start_a_list_and_retrieve_it_later
    self.assertIn('To-Do', self.browser.title)
AssertionError: 'To-Do' not found in u'OperationalError at /'

----------------------------------------------------------------------
Ran 1 test in 5.945s

FAILED (failures=1)

Creating Our Production Database with migrate
การสร้างฐานข้อมูล
แก้ไขไฟล์ superlists/settings.py
 
[...]
# Database
# https://docs.djangoproject.com/en/1.7/ref/settings/#databases

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
    }
}

แก้ไขไฟล์ lists/templates/home.html.

  {% for item in items %}
        <tr><td>{{ forloop.counter }}: {{ item.text }}</td></tr>
    {% endfor %}

ทำการลบดาต้าเบส และสร้างดาต้าเบสอันใหม่ขึ้นมาโดยใช้คำสั่ง

$ python manage.py syncdb

และทำการรันไฟล์ functional_tests จะมีหน้า browser เด้งขึ้นมาดังรูป

และโปรแกรมจะแสดงผลว่ารันผ่าน

$ python functional_tests.py 
F
======================================================================
FAIL: test_can_start_a_list_and_retrieve_it_later (__main__.NewVisitorTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "functional_tests.py", line 59, in test_can_start_a_list_and_retrieve_it_later
    self.fail('Finish the test!')
AssertionError: Finish the test!

----------------------------------------------------------------------
Ran 1 test in 7.346s

FAILED (failures=1)

ทำการคอมมิทโดยใช้ชื่อว่า "Redirect after Post, and sshow all item in template"

$ git commit -m"Redirect after Post, and show all items in template"




ไม่มีความคิดเห็น:

แสดงความคิดเห็น