ทดสอบ Homepage อย่างง่ายด้วย Unit Tests !!
จาก chapter ที่แล้ว ที่เรารัน functional test ไม่ผ่านเพราะเราต้องการให้มีคำว่า To-Do ใน title ของ homepage
คราวนี้แหละ จะถึงเวลาที่เราจะเริ่มทำแอพลิเคชั่น
เริ่มทำ Django App และทำ Unit Tests !!
สร้าง app ชื่อ lists สำหรับทำ To-Do lists
$ python3 manage.py startapp lists
ความแตกต่างระหว่าง Functional Tests และ Unit
Tests
Functional Test เป็นการเทสจากภายนอก ในมุมมองของผู้ใช้ ส่วน
Unit Test จะเป็นการเทสจากภายใน ในมุมมองของ Programmer
TDD ประกอบด้วยเทสทั้งสองแบบ โดยจะมีลำดับการทำงานดังนี้
1.เราจะเริ่มจากการเขียน Functional Test เพื่อระบุการทำงานของแอพพลิชั่น
จากมุมมองของผู้ใช้
2.หลังจากเราเทส Functional Tests ไม่ผ่าน
เราก็จะคิดถึงวิธีการที่จะเขียนโค้ดเพื่อให้เทสผ่าน โดยเราจะใช้ Unit test อย่างน้อย 1 Unit
Tests เพื่อกำหนดว่าโค้ดของเราควรจะเป็นยังไง โดยแนวคิดคือ โค้ดแต่ละบรรทัดควรจะถูกเทสโดย Unit tests อย่างน้อย 1 Unit test
3.หลังจากเราเทส Unit Tests ไม่ผ่าน ให้เขียนโค้ดให้น้อยที่สุดเพื่อให้เทสผ่าน เราอาจจะทำ step 2 และ 3 หลายๆครั้ง จนกว่าเราคิดว่า Functional Test น่าจะเทสผ่านเยอะขึ้น
4.ลองเทส Functional Tests อีกรอบ และดูว่าเทสผ่านหรือยัง ถ้ายังไม่ผ่านให้เขียน Unit Tests และเขียนโค้ดเพิ่ม
Unit Tests ใน Django
เปิดไฟล์ tests.py ใน /superlists/lists
จะเห็นได้ว่า Django แนะนำให้เราใช้ TestCase ซึ่งเป็น unittest พื้นฐานที่ Django เพิ่มเติมบางส่วนมาเพื่อใช้งานกับ Django โดยเฉพาะ
สำหรับ Functional Tests เรารันด้วยตัวเองโดยตรง แต่ Unit test ที่เรากำลังเขียนจะรันโดยอัตโนมัติโดย Test runner
แก้ไขไฟล์ tests.py เป็นดังนี้
from django.test import TestCase
class SmokeTest(TestCase):
def test_bad_maths(self):
self.assertEqual(1 + 1, 3)
รันจากนั้นให้เรารันเทส โดย $ python3 manage.py test
จะเกิด Error ขึ้นมา
ดูเหมือนว่า test จะใช้งานได้
ให้ commit เก็บไว้
$ git add lists
$ git commit -m"Add app for lists, with deliberately failing unit test"
ต่อมา เราตั้งเป้าจะเทส 2 อย่าง
1.เราสามารถ resolve URL ที่ / ไปหา view ที่เราสร้างได้ไหม
2.เราสามารถทำให้ view return HTML ที่ทำให้ Functional Test ผ่านได้
เริ่มจากอย่างแรก แก้ไขไฟล์ tests.py
from django.core.urlresolvers import resolve
from django.test import TestCase
from lists.views import home_page #
class HomePageTest(TestCase):
def test_root_url_resolves_to_home_page_view(self):
found = resolve('/') #
self.assertEqual(found.func, home_page)
เมื่อเราลองรันเทส เราจะรันไม่ผ่าน
ให้เราเขียนโค้ดเพื่อให้เทสผ่าน
แก้ไฟล์ views.py ใน /superlists/lists
from django.shortcuts import render
# Create your views here.
home_page = None
เมื่อรันเทส
จากการเทสด้านบน ทำให้เรารู้ว่า Django หา URL mapping ของ / ไม่เจอ
แก้ไฟล์ urls.py ใน /superlists/superlists
urlpatterns = patterns('',
url(r'^$', 'lists.views.home_page', name='home'),
)
และแก้ views.py ใน /superlists/lists
from django.shortcuts import render
# Create your views here.
def home_page():
pass
เมื่อลองรันเทสดู
เทสผ่าน เย้ !!
commit เก็บไว้
ต่อมาเราเทสอย่างที่สองกัน
ใส่โค้ด from django.http import HttpRequest เข้าไปใน Unit test
เพิ่ม Method ที่ไว้เทส Unit Test นี้เข้าไป
def test_home_page_returns_correct_html(self):
request = HttpRequest() #
response = home_page(request) #
self.assertTrue(response.content.startswith(b'<html>')) #
self.assertIn(b'<title>To-Do lists</title>', response.content) #
self.assertTrue(response.content.endswith(b'</html>')) #
รันเทส
แก้ไข views.py เพื่อให้เทสผ่าน ดูว่าเทสไม่ผ่านเพราะอะไร และเพิ่มโค้ดไปเรื่อยๆ จนสุดท้ายใน views.py จะมีหน้าตาแบบนี้
from django.shortcuts import render
from django.http import HttpResponse
# Create your views here.
def home_page(request):
return HttpResponse('<html><title>To-Do lists</title></html>')
แล้วเราก็จะเทสผ่าน
หลังจากนั้น ลองรัน Functional Test
ก็จะพบว่าเทสผ่าน !!
commit เก็บไว้ !!