วันพฤหัสบดีที่ 19 มิถุนายน พ.ศ. 2557

รายการสินค้า

 เปรียบเทียบราคาสินค้า
1. ดัชมิลล์ดีมอลต์ รสช็อคโกแลต
    ขนาด 180 มล. แพค 4 กล่อง ราคา 40 บาท    :    ขนาด 90 มล. แพค 4 กล่อง ราคา 21 บาท

2. เป๊ปซี่
    ขนาด 245 มล. แพค 6 กระป๋อง ราคา 55 บาท    :    ขนาด 245 มล. 1 กระป๋อง ราคา 11 บาท

3. มันฝรั่งทอดกรอบ เลย์
    ขนาด 55 กรัม แพค 6 ถุง ราคา 99 บาท    :    ขนาด 55 กรัม 1 ถุง ราคา 20 บาท

4. โออิชิ กรีนที รสต้นตำรับ
    ขนาด 250 มล. แพค 4 กล่อง ราคา 34 บาท    :    ขนาด 250 มล. 1 กล่อง ราคา 10 บาท

5. เคลียร์ แชมพู กลิ่นซากูระ
    ขนาด 480 มล. 1 ขวด ราคา 179 บาท    :    ขนาด 340 มล. 1 ขวด ราคา 99 บาท


วันอาทิตย์ที่ 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"




วันพฤหัสบดีที่ 5 มิถุนายน พ.ศ. 2557

Chapter 4. What Are We Doing with All These Tests?

Chapter 4. What Are We Doing with All These Tests?

Using Selenium to Test User Interactions
   ใช้ Selenium ในการทดสอบปััญหา เมื่อทำการทดสอบ functional_tests.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 20, in test_can_start_a_list_and_retrieve_it_later     self.fail('Finish the test!')  #6 AssertionError: Finish the test! ---------------------------------------------------------------------- Ran 1 test in 5.422s FAILED (failures=1)

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

from selenium import webdriver
import unittest

class NewVisitorTest(unittest.TestCase):  #1

    def setUp(self):  #2 
        self.browser = webdriver.Firefox()
     self.browser.implicitly_wait(3)

    def tearDown(self):  #3
        self.browser.quit()

    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
        # to check out its homepage
        self.browser.get('http://localhost:8000')

        # She notices the page title and header mention to-do lists
        self.assertIn('To-Do', self.browser.title)
        header_text = self.browser.find_element_by_tag_name('h1').text
        self.assertIn('To-Do', header_text)

        # She is invited to enter a to-do item straight away
        inputbox = self.browser.find_element_by_id('id_new_item')
        self.assertEqual(
                inputbox.get_attribute('placeholder'),
                'Enter a to-do item'
        )

        # She types "Buy peacock feathers" into a text box (Edith's hobby
        # is tying fly-fishing lures)
        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)

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

        # 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!')

        # The page updates again, and now shows both items on her list

if __name__ == '__main__':  #7
    unittest.main()  #8

ทำการรันไฟล์ functional_tests.py จะมี browser เด้งขึ้นมา 

และโปรแกรม Error ดังนี้ คือ ไม่สามารถหาองค์ประกอบของ method : tagname , selector : h1

$ 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 20, in test_can_start_a_list_and_retrieve_it_later
    header_text = self.browser.find_element_by_tag_name('h1').text
  File "/usr/local/lib/python2.7/dist-packages/selenium-2.41.0-py2.7.egg/selenium/webdriver/remote/webdriver.py", line 319, in find_element_by_tag_name
    return self.find_element(by=By.TAG_NAME, value=name)
  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":"tag name","selector":"h1"}' ; Stacktrace: 
    at FirefoxDriver.prototype.findElementInternal_ (file:///tmp/tmpKvc9ez/extensions/fxdriver@googlecode.com/components/driver_component.js:8905)
    at fxdriver.Timer.prototype.setTimeout/<.notify (file:///tmp/tmpKvc9ez/extensions/fxdriver@googlecode.com/components/driver_component.js:396) 

----------------------------------------------------------------------
Ran 1 test in 8.403s

FAILED (errors=1)

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

$ git diff
diff --git a/functional_tests.py b/functional_tests.py
index b6322b7..23fe36f 100644
--- a/functional_tests.py
+++ b/functional_tests.py
@@ -16,11 +16,37 @@ class NewVisitorTest(unittest.TestCase):  #1
         self.browser.get('http://localhost:8000')
 
         # She notices the page title and header mention to-do lists
-        self.assertIn('To-Do', self.browser.title)  #5
-        self.fail('Finish the test!')  #6
+        self.assertIn('To-Do', self.browser.title)
+        header_text = self.browser.find_element_by_tag_name('h1').text
+        self.assertIn('To-Do', header_text)
 
         # She is invited to enter a to-do item straight away
-        #[...rest of comments as before]
+        inputbox = self.browser.find_element_by_id('id_new_item')
+        self.assertEqual(
+                inputbox.get_attribute('placeholder'),
+                'Enter a to-do item'
+        )
+
+        # She types "Buy peacock feathers" into a text box (Edith's hobby
:

คอมมิทโดยใช้ชื่อ "Functional test now checks we can input a to-do item"

$ git commit -am "Functional test now checks we can input a to-do item"
[master 935ab70] Functional test now checks we can input a to-do item
 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

 1 file changed, 29 insertions(+), 3 deletions(-)

The “Don’t Test Constants” Rule, and Templates to the Rescue
"อย่าทดสอบค่าคงที่" ทำการทดสอบหน่วยใน list/tests.py
ทำการรันไฟล์ test จะแสดงผลการรันผ่าน ดังนี้

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

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

จากนั้นสร้างโฟล์เดอร์ใหม่ชื่อ templates ใน list และสร้างไฟล์ home.html จะเป็น lists/templates/home.html และทำการแก้ไขไฟล์ดังนี้

<html>
    <title>To-Do lists</title>
</html>

 และแก้ไขไฟล์ lists/views.py ดังนี้ เพื่อจะเรียกใช้ไฟล์ home.html

from django.shortcuts import render

def home_page(request):
    return render(request, 'home.html')

ทำการรันไฟล์ test จะแสดงผลดังนี้ คือ โปรแกรมจะหา home.html ไม่เจอ

$ 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 17, in test_home_page_returns_correct_html
    response = home_page(request)  #2
  File "/home/jutamas/Desktop/summer/superlists/lists/views.py", line 4, in home_page
    return render(request, 'home.html')
  File "/usr/local/lib/python2.7/dist-packages/django/shortcuts/__init__.py", line 53, in render
    return HttpResponse(loader.render_to_string(*args, **kwargs),
  File "/usr/local/lib/python2.7/dist-packages/django/template/loader.py", line 162, in render_to_string
    t = get_template(template_name)
  File "/usr/local/lib/python2.7/dist-packages/django/template/loader.py", line 138, in get_template
    template, origin = find_template(template_name)
  File "/usr/local/lib/python2.7/dist-packages/django/template/loader.py", line 131, in find_template
    raise TemplateDoesNotExist(name)
TemplateDoesNotExist: home.html

----------------------------------------------------------------------
Ran 2 tests in 0.135s

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

แก้ไขไฟล์ superlists/settings.py โดยการเพิ่ม list เข้าไปเพราะ templates อยู่ใน lists

INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'lists',
)

ทำการรันไฟล์ test จะแสดงผลดังนี้ คือ Error เนื่องจากต้องมี </html> ปิดท้าย

$ python manage.py test
Creating test database for alias 'default'...
F.
======================================================================
FAIL: test_home_page_returns_correct_html (lists.tests.HomePageTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "/home/jutamas/Desktop/summer/superlists/lists/tests.py", line 20, in test_home_page_returns_correct_html
    self.assertTrue(response.content.endswith(b'</html>'))  #5
AssertionError: False is not true

----------------------------------------------------------------------
Ran 2 tests in 0.005s

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

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

self.assertTrue(response.content.strip().endswith(b'</html>'))

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

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

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

แก้ไขไฟล์ lists/tests.py เพื่อเป็นการเรียกใช้ไฟล์ templates แต่จะบันทึกผลเป็นสตริง

from django.template.loader import render_to_string
[...]

    def test_home_page_returns_correct_html(self):
        request = HttpRequest()
        response = home_page(request)
        expected_html = render_to_string('home.html')
        self.assertEqual(response.content.decode(), expected_html)

On Refactoring

ใช้คำสั่ง git status เพื่อดูสถานะไฟล์

$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified:   lists/tests.py
# modified:   lists/tests.py~
# modified:   lists/views.py
# modified:   superlists/settings.py
# modified:   superlists/settings.pyc
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
# Untitled Document~
# functional_tests.py~
# lists/templates/
# lists/views.py~
# superlists/settings.py~
# superlists/urls.py~
no changes added to commit (use "git add" and/or "git commit -a")

ใช้คำสั่ง git add . เพื่อ add ไฟล์เข้ามา

$ git add .

ใช้คำสั่ง git diff --staged ดูการแก้ไขไฟล์

$ git diff --staged
diff --git a/Untitled Document~ b/Untitled Document~
new file mode 100644
index 0000000..e69de29
diff --git a/functional_tests.py~ b/functional_tests.py~
new file mode 100644
index 0000000..b6322b7
--- /dev/null
+++ b/functional_tests.py~
@@ -0,0 +1,26 @@
+from selenium import webdriver
+import unittest
+
+class NewVisitorTest(unittest.TestCase):  #1
+
+    def setUp(self):  #2 
+        self.browser = webdriver.Firefox()
+       self.browser.implicitly_wait(3)
+
+    def tearDown(self):  #3
+        self.browser.quit()
+
+    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
:

ใช้คำสั่ง git commit -m "Refactor home page view to use a template"
git commit -m"Refactor home page view to use a template"
[master b417b4a] Refactor home page view to use a template
 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

 10 files changed, 154 insertions(+), 8 deletions(-)
 create mode 100644 Untitled Document~
 create mode 100644 functional_tests.py~
 create mode 100644 lists/templates/home.html
 create mode 100644 lists/templates/home.html~
 create mode 100644 lists/views.py~
 create mode 100644 superlists/settings.py~
 create mode 100644 superlists/urls.py~

A Little More of Our Front Page
แก้ไขไฟล์ lists/templates/home.html ดังนี้
 
<html>
    <head>
        <title>To-Do lists</title>
    </head>
    <body>
        <h1>Your To-Do list</h1>
    </body>
</html>

ทำการรันไฟล์ functional_tests.py จะแสดง browser ขึ้นมาดังนี้


และโปรแกรมจะแสดงผล Error ดังนี้ คือ ไม่สามารถหา meyhod : id , selector : id_new_item ได้
$ 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 24, in test_can_start_a_list_and_retrieve_it_later
    inputbox = self.browser.find_element_by_id('id_new_item')
  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_new_item"}' ; Stacktrace: 
    at FirefoxDriver.prototype.findElementInternal_ (file:///tmp/tmpqHTZux/extensions/fxdriver@googlecode.com/components/driver_component.js:8905)
    at fxdriver.Timer.prototype.setTimeout/<.notify (file:///tmp/tmpqHTZux/extensions/fxdriver@googlecode.com/components/driver_component.js:396) 

----------------------------------------------------------------------
Ran 1 test in 8.079s

FAILED (errors=1)

ทำการแก้ไขไฟล์ lists/templates/home.html คือการเพิ่มช่องใส่ข้อมูล
[...] 
        <h1>Your To-Do list</h1>
        <input id="id_new_item" />
    </body>[...]

ทำการรันไฟล์ functional_tests.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 27, in test_can_start_a_list_and_retrieve_it_later
    'Enter a to-do item'
AssertionError: u'' != 'Enter a to-do item'

----------------------------------------------------------------------
Ran 1 test in 4.872s

FAILED (failures=1)

lists/templates/home.html.
[...]
    <input id="id_new_item" placeholder="Enter a to-do item" />
[...]

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

และโปรแกรม 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/tmpQbTAZ2/extensions/fxdriver@googlecode.com/components/driver_component.js:8905)
    at fxdriver.Timer.prototype.setTimeout/<.notify (file:///tmp/tmpQbTAZ2/extensions/fxdriver@googlecode.com/components/driver_component.js:396) 

----------------------------------------------------------------------
Ran 1 test in 15.109s

FAILED (errors=1)


แก้ไขไฟล์ lists/templates/home.html ดังนี้

[...]
    <input id="id_new_item" placeholder="Enter a to-do item" />
    <table id="id_list_table">
    </table>
  </body>
[...]

ทำการรันไฟล์ functional_tests.py จะแสดงผลดังนี้ คือ row.text == 1 ไม่เป็นความจริง
$ 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
    any(row.text == '1: Buy peacock feathers' for row in rows)
AssertionError: False is not true

----------------------------------------------------------------------
Ran 1 test in 15.094s

FAILED (failures=1)

ทำการแก้ไขไฟล์ 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"
    )

ทำการรันไฟล์ functional_tests.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 15.179s

FAILED (failures=1)



$ git diff
diff --git a/functional_tests.py b/functional_tests.py
index 23fe36f..5487abb 100644
--- a/functional_tests.py
+++ b/functional_tests.py
@@ -1,15 +1,16 @@
 from selenium import webdriver
+from selenium.webdriver.common.keys import Keys
 import unittest
 
 class NewVisitorTest(unittest.TestCase):  #1
 
     def setUp(self):  #2 
         self.browser = webdriver.Firefox()
-       self.browser.implicitly_wait(3)
+       self.browser.implicitly_wait(10)
 
     def tearDown(self):  #3
         self.browser.quit()
-
+       
     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
         # to check out its homepage
:
    

ใช้คำสั่งคอมมิท ใช้ชื่อ "Front page HTML now generated from a template"
$ git commit -am"Front page HTML now generated from a template"
[master b47c562] Front page HTML now generated from a template
 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

 4 files changed, 61 insertions(+), 11 deletions(-)