วันเสาร์ที่ 7 กุมภาพันธ์ พ.ศ. 2558

TDD - 4 What Are We Doing with All These Tests?

Chapter 04 - What Are We Doing with All These Tests?  

ในการ test ครั้งนี้จะเป็นการ test ในส่วนของ การ รันค่าจากไฟล์ html ที่ตั้งให้เป็น
Home page ซึ่ง Home page ในที่นี้จะมีโค้ด HTML ที่จะ render ให้ client ผู้ซึ่ง request เข้ามา
โดย functional_tests.py นี้นั้นโดยที่รู้ ๆ กันอยู่ว่า เป็นในส่วนของกา


 รตรวจสอบการแสดงผลในมุมมองของผู้ใช้ว่ามี object นี้ไหม มีการแสดงผลที่ถูกต้องหรือเปล่า เมื่อให้ input เป็นในรูปแบบนี้แล้ว

output ตรงตาม concept ที่ตั้งใจไว้หรือเปล่า โดยจะมีการเรียกใช้ function ในการตรวจสอบ
อย่างเช่น self.assertIn('To-Do', self.browser.title)
เป็นการตรวจสอบค่า ที่อยู่ใน title ของ browser ของเราว่ามีคำว่า 'To-Do' หรือเปล่าหากไม่มีก็จะขึ้น error และปิดโปรแกรมลง ตามฟังก์ชัน teardown(self){...} (เป็นฟังก์ชันที่จะเรียกใช้เมื่อมีการ error)
ของ platform หรือมีการ return ค่าออกมาเป็น เท็จ (ไม่เห็น object)
ในตอนแรกนั้น functional_tests.py จะทำการเรียก server ที่รันไว้ ที่ localhost:8000 จากในบรรทัด
 self.browser.get('http://localhost:8000') โดย urls.py ก็จะทำหน้าที่ส่งต่อให้ function home_page ในไฟล์ lists/views.py โดยไฟล์ views.py นั้นก็จะทำหน้าที่โดยการแสดง home page ออกมา  ซึ่งโค้ดนั้นจะถูกตรวจสอบโดย test.py ว่าถูกต้องตามหลักไวยากรณ์ไหม มีแทกอะไรที่ขาดไปบ้างจาก platform ที่เราต้องการ 
เช่น ใช้ฟังก์ชั่น self.assertIn(b'<title>To-Do lists</title>', response.content)
หมายความว่าให้เช็คว่าในข้อความที่ได้ response ออกมานั้นมีคำว่า '<title>To-Do lists</title>' หรือไม่
หลังจากที่เราสร้างไฟล์เรียบร้อยแล้วก็ให้ใส่ code ลงไปในไฟล์โดยเริ่มต้นให้ลองใส่
===============views.py============== 
from django.shortcuts import render

def home_page(request):
    return render(request, 'home.html') 
เมื่อได้ทดสอบเขียนโค้ดดูแล้วลองรันโดย $ python3 manage.py test

 
ซึ่งในตอนแรกนั้นยังไม่ได้ทำการสร้างไฟล์ home page ก็มี error แจ้งเตือนขึ้นมาว่าไม่พบไฟล์ดังกล่าว ต่อมาจึงสร้างไฟล์ home.html ขึ้นใน directory -> lists/templates/ และทำการเขียนโค้ดลงในไฟล์ และเพิ่มโค้ดลงในส่วนของ settings.py file
===============home.html============== 
<html>
    <title>To-Do lists</title>
</html> 
 
==============Settings.py=============
INSTALLED_APPS = (
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'lists',
) 
หลังจากนั้นทดสอบรันโค้ดอีกรอบ $ python3 manage.py test
error ที่แจ้งเตือนว่าไม่พบไฟล์นั้น ได้หายไปแล้วกลายเป็นแจ้งเตือน error เกี่ยวกับ code ที่ return ค่า
กลับมาแทน หลังจากนั้นทดสอบเปลี่ยน code ที่ test.py โดยให้ที่การแบ่งค่าออกมาเป็น บรรทัดแทน

============================tests.py========================== 
self.assertTrue(response.content.strip().endswith(b'</html>')) 
ทดสอบดูอีกที $ python3 manage.py test ได้ผลลัพธ์ออกมาว่า การตรวจเช็ตไม่มีข้อผิดพลาดของ syntax
สามารถเปลี่ยนรูปแบบโค้ดเป็นการ decode ได้โดยเปลี่ยนรูปแบบ code ของ tests.py

============================tests.py========================== 
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)
โดยผลที่ได้ก็จะเหมือนเดิม
ทดสอบการเปลี่ยนโค้ดของ home.html
===============================home.html=========================== 
<html>
    <head>
        <title>To-Do lists</title>
    </head>
    <body>
        <h1>Your To-Do list</h1>
        <input id="id_new_item" placeholder="Enter a to-do item" /> 
    </body>
</html>
โดยโค้ดในส่วนของ input นั้นจะเป็น input ในรูปแบบ default คือ textbox โดยที่ functional_tests.py
จะมีโค้ด inputbox = self.browser.find_element_by_id('id_new_item') ที่จะนำเอาค่า ของ object ใน
id : id_new_item เก็บไว้ในตัวแปรที่ชื่อ input เมื่อโปรแกรมเรียกใช้คำสั่ง
self.assertEqual(inputbox.get_attribute('placeholder'),'Enter a to-do item') ก็จะมีการเช็คค่า ว่าค่า placeholder ใน object นั้นตรงกับ 'Enter a to-do item' หรือเปล่า หากไม่ตรงก็จะ error และไปที่
function teardown โดยอัตโนมัติ ลองเพิ่ม หลังจากนั้นก็ทำการ git commit ค่าที่ปลี่ยนแปลงไป

วันอาทิตย์ที่ 1 กุมภาพันธ์ พ.ศ. 2558

TDD - 03 Testing a Simple Home Page with Unit Tests

Chapter 3 - Testing a Simple Home Page with Unit Tests 

เมื่อคราวที่แล้วได้ทดสอบการ ใช้ git ในการสร้างไฟล์ขึ้นมาและเรียนรัน ไฟล์ที่สร้างขึ้น
และมีการ set git ใน directory ที่เราได้สร้างขึ้นมา
ในครั้งนี้จะเป็นการสร้าง Home page อย่างง่าย ๆ และการ ทดสอบการรัน 
file Homepage ที่สร้างขึ้น และแก้บัคกับสิ่งที่เกิดขึ้น
เนื่องจากว่า ผมได้ทดสอบ run ไปแล้ว 1 รอบ เมื่อกลับไปลอง run ใหม่แล้วค่าที่ 
error มันไม่หมือนเดิมจึงไม่สามารถที่จะ run output ออกมาให้ได้ทั้งหมดครับ
เริ่มต้น สร้าง List ในโฟลเดอร์ที่เราเริ่มต้นโปรเจคขึ้น ในที่นี้
ให้เราสร้าง app list โดยพิมพ์โค้ดลงไปดังนี้





  •   python3 manage.py startapp lists

  • superlists/
    ├── db.sqlite3
    ├── functional_tests.py
    ├── lists
    │   ├── admin.py
    │   ├── __init__.py
    │   ├── migrations
    │   │   └── __init__.py
    │   ├── models.py
    │   ├── tests.py
    │   └── views.py
    ├── manage.py
    └── superlists
        ├── __init__.py
        ├── __pycache__
        ├── settings.py
        ├── urls.py
        └── wsgi.py 
    
    
    โดยหลังจากที่ได้ run code แล้วก็จะมี directory หน้าตาแบบนี้ขึ้นที่ directory ที่เราสร้างโปรเจคขึ้นมา
    โดยหลังจากนั้นก็ได้ทำการเปลี่ยนแปลงข้อมูลในไฟล์ test.py ที่อยู่ใน /list/
    ดังนี้
    from django.test import TestCase
    
    class SmokeTest(TestCase):
    
        def test_bad_maths(self):
            self.assertEqual(1 + 1, 3)
    แล้วหลังจากนั้น ทดลอง run test โดยใส่โค้ดดังนี้

    python3 manage.py test
    
    หลังจากนั้น หากผิดพลาดเมื่อได้ค่า error มาเราก็จะนำข้อผิดพลาดที่เกิดขึ้นมา
    แก้ไข โดยจากตัวอย่างไม่ได้ผิดพลาดแต่อย่างใดแต่ได้ผลลัพธ์ที่ว่า 2 != 3
    test.py เป็นไฟล์ที่เราเขียนขึ้นมาเพื่อใช้ทดสอบข้อผิดพลาดต่าง ๆ ภายใน TDD 
    ซึ่งผลลัพธ์สามารถที่จะทดสอบได้โดยทดลอง run ได้ใน python
    ส่วน view.py เป็นในส่วนของมุมมองที่จะแสดงผลให้ client ดู 
    ทดสอบการรันในส่วนของ view.py แล้ว จะได้ error เกี่ยวกับในส่วนของ
    function การแสดงผลออกมา ว่ามีการ error ในส่วนใดและจะสามารถนำในส่วนที่
    มันฟ้องว่า error ในส่วนใด กลับมาแก้ไขได้
    ในส่วนของ urls.py จะเป็นส่วนของการ map client ไปสู่ url ต่างๆที่ client 
    เรียกขอมาซึ่งจะมี error ขึ้นมาในส่วนของ url ที่ผิดพลาดเช่น
    ภายใน urls มีโค้ดว่า
    urlpatterns = patterns('',
        # Examples:
        url(r'^$', 'superlists.views.home', name='home'),
        # url(r'^blog/', include('blog.urls')),
    
        # url(r'^admin/', include(admin.site.urls)),
    )
    เมื่อ run python manage.py test แล้วได้ output ออกมาดังนี้

    django.core.exceptions.ViewDoesNotExist: Could not import
    superlists.views.home. Parent module superlists.views does not exist.
     
    มันฟ้องว่าไม่พบ file ที่เราค้นหาอยู่ เนื่องจากว่าใส่โค้ดที่จะค้นหาในส่วนของไฟล์ url ผิดพลาด
    จึงไม่สามารถที่จะค้นหาพบได้ 
    
    
    ค่าที่ error ออกมานั้นมักจะมี วิธีแก้ไขออกมาให้ด้วยเสมอ ซึ่งวิธีแก้ไขนี้เอง
    ที่เราสามารถที่จะนำไปปรับแก้โค้ดของเราทีละนิด ซึ่งทุกครั้งที่แก้ไข หากโปรแกรมนั้นยัง
    error อยู่ก็มักที่จะมี solution หรือแนวทางในการแก้ไขปัญหาต่อ ๆ ไปที่จะให้เราทำไปตาม
    ขั้นตอน จบกว่าที่มันจะไม่ error และสามารถที่จะ run ได้ตามปกติ