ทำไมต้องทำ Unit Testing ?
![](https://b2dmain-ruk.cdn.jelastic.net/wp-content/uploads/2020/04/jeshoots-com-2vD8lIhdnw-unsplash-1024x683.jpg)
เวลาที่เราเขียนโค้ดอะไรขึ้นมาสักอย่าง สิ่งที่จะเจอตลอดก็คือ bug และ error ต่างๆ ไม่ว่าจะเป็นโปรแกรมเล็กๆไปจนถึงระบบขนาดใหญ่ และสิ่งที่ต้องทำก็คือการ debug หรือแก้ bug เหล่านั้นนั่นเอง ซึ่งยิ่งโค้ดที่เราเขียนมาเยอะและซับซ้อน การจะงมหาข้อผิดพลาดในโปรแกรมบางครั้งก็ใช้เวลานานเอามากๆ เพราะไม่รู้จะเริ่มตรงไหน ไม่มั่นใจว่าทุกฟังก์ชันที่ทำงานร่วมกันมันทำงานได้สมบูรณ์รึเปล่า นี่จึงเป็นสาเหตุว่าทำไมเราจึงควรทำ Unit Test เพราะเราจะได้มั่นใจว่าส่วนต่างๆของโปรแกรมที่ทดสอบแล้วจะไม่ได้เป็นสาเหตุของ bug ที่เกิดขึ้นระหว่างการพัฒนาโปรแกรม
เริ่มต้นสร้าง Unit Test ตัวแรก
สำหรับการทดลองเขียน Unit Test ในคราวนี้เราจะใช้ Python Module ที่มีชื่อว่า unit test ที่มีความสามารถตรงตามชื่อเลย เรามาลองดูการทดสอบด้วย test case แบบต่างๆกันเลย
เริ่มจากทำการ import module ที่เราจะใช้กันด้วยคำสั่ง
import unittest
และเขียนฟังก์ชันที่จะใช้ทดสอบโดยมีข้อกำหนดว่าชื่อฟังก์ชันต้องขึ้นต้นด้วย “test” เช่น
def test_add(self)
...
def testMultiply(self)
…
โดยฟังก์ชันทดสอบของเรานั้นจะต้องใส่เอาไว้ในคลาสถึงจะใช้งานได้
class TestNumber(unittest.TestCase):
...
พอเอามาเขียนรวมกันก็จะได้โค้ดออกมาหน้าตาแบบนี้
import unittest
class TestNumber(unittest.TestCase):
def test_add(self):
self.assertEqual(1 + 2, 3)
self.assertEqual(2 + 2, 4)
def testMultiply(self):
self.assertEqual(1 * 1, 1)
self.assertEqual(1 * 2, 2)
self.assertEqual(2 * 4, 8)
if __name__ == '__main__':
unittest.main()
ลองกดรันก็จะได้ผลลัพธ์ออกมา
..
----------------------------------------------------------------------
Ran 2 tests in 0.000s
OK
ในโค้ดตัวอย่างนั้นส่วนที่สำคัญก็คือตรงที่เราใช้ตรวจสอบว่าจะผ่านหรือมไม่ผ่าน test case นั้นๆ ซึ่งก็คือ“assertEqual” โดยจะใช้สำหรับตรวจสอบว่าค่าใส่ใส่เข้าไปนั้นเท่ากันหรือไม่ อย่างเช่นถ้าเราใส่ค่าเข้าไปว่า assertEqual(a, b) ก็จะเป็นการตรวจสอบว่า a นั้นเท่ากับ b หรือไม่ นอกจาก assertEqual แล้วก็ยังมีฟังก์ชันอื่นๆของ unittest module ให้เราได้ใช้กันตามตารางด้านล่างนี้
จากเว็บ: https://docs.python.org/3/library/unittest.html#unittest.TestCase
![](https://b2dmain-ruk.cdn.jelastic.net/wp-content/uploads/2020/04/unittest_function.png)
แนวคิด Test-Driven Development (TDD) ที่ช่วยให้เราทำ Unit Testing สนุกขึ้น
![](https://b2dmain-ruk.cdn.jelastic.net/wp-content/uploads/2020/04/quino-al-P05VBPvNr3s-unsplash-1024x683.jpg)
สำหรับคนที่เคยอ่านเกี่ยวกับการทดสอบโปรแกรมมาบ้างก็อาจจะเคยผ่านตากับ TDD หรือ Test-Driven Development มาบ้าง หลังจากที่รู้จักกับ Unit Test แบบคร่าวๆกันแล้วเราลองมาดูเรื่อง TDD ต่อกัน แนวคิดของ TDD ก็คือให้เราเขียน Test Case ที่อยากจะทดสอบดูก่อน แล้วลองกดให้ทำงานดู แน่นอนหละว่ามันอาจจะยังทำงานได้ไม่ถูกต้อง หรือ ยังทำงานไม่ได้เลย เพราะเราไม่ได้ขเียนโค้ดไว้ ต่อมาก็ปรับแต่งโค้ดให้ทำงานได้ถูกต้อง แล้ววนซ้ำไปทีละส่วน ซึ่งขึ้นตอนมันกลับกันกับตอนที่เราเขียนโค้ดแบบปกติ ถ้ายังไม่เห็นภาพงั้นเราลองไปดูตัวอย่างกัน
ลองทำ TDD ด้วย Python แบบง่าย ๆ
เรามาลองเขียนโค้ดสร้างเครื่องคิดเลขกัน เริ่มจากเขียน test case ด้วย unit test เพื่อทดสอบฟังก์ชันการบวกของเครื่องคิดเลข
import unittest
class MyTest(unittest.TestCase):
def test_hello_world(self):
myCal = Calculator();
self.assertEqual(myCal.add_num(1,2), 3)
if __name__ == '__main__':
unittest.main()
Output:
E
======================================================================
ERROR: test_hello_world (__main__.MyTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "main.py", line 5, in test_hello_world
myCal = Calculator();
NameError: name 'Calculator' is not defined
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (errors=1)
จะเห็นว่ามี error ออกมาเพราะว่าเรายังไม่ทันได้เริ่มสร้าง class Calculator ขึ้นมาเลยนั่นเอง งั้นต่อไปเราก็ลงมือสร้าง Calculator พร้อมฟังก์ชัน add_num เพื่อให้ error นี้หายไปกัน
import unittest
class Calculator():
def add_num(self, a, b):
return a + b
class MyTest(unittest.TestCase):
def test_hello_world(self):
myCal = Calculator();
self.assertEqual(myCal.add_num(1, 2), 3)
if __name__ == '__main__':
unittest.main()
Output:
.
----------------------------------------------------------------------
Ran 1 test in 0.000s
OK
คราวนี้พอรันทดสอบก็จะผ่านเป็นอันเรียบร้อยแล้ว และถ้าเราจะทำฟังก์ชันสำหรับการลบเลขก็วนกลับไปเริ่มเขียน test case ก่อนเหมือนตอนทำกับฟังก์ชันบวกเลขนั่นเอง
ได้เห็นตัวอย่างง่ายๆเกี่ยวกับการเขียนเทสกันไปแล้ว ก็ลองตัดสินใจเอาไปคิดดูว่าโปรเจคที่เราทำอยู่นั้นเหมาะที่จะทำ Unit Test หรือพัฒนาด้วย TDD รึเปล่า เพราะนอกจากที่ยกตัวอย่างมาในวันนี้ก็ยังมีวิธีการเทสแบบอื่นๆอีกหลายวิธี ต้องเลือกเลือกหาวิธีที่เหมาะกับงานของเราเพื่อจะได้เขียนโค้ดได้อย่างมีความสุขกันนะครับ