วันพฤหัสบดีที่ 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(-)

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

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