目次  
1. Python unittest คืออะไร?
unittest เป็นเฟรมเวิร์กการทดสอบหน่วยที่รวมอยู่ในไลบรารีมาตรฐานของ Python ซึ่งเป็นเครื่องมือสำคัญในการรับประกันคุณภาพของโค้ด ทำให้ผู้พัฒนาสามารถทดสอบแต่ละส่วนของโค้ดได้อย่างอิสระและช่วยให้ค้นหา bug ได้ตั้งแต่เนิ่นๆ นอกจากนี้ยังช่วยตรวจสอบว่าการเปลี่ยนแปลงโค้ดในระหว่างการพัฒนาอย่างต่อเนื่องไม่ได้ทำลายฟังก์ชันที่มีอยู่ความสำคัญของการทดสอบหน่วย
เมื่อโค้ดซับซ้อนมากขึ้น การตรวจสอบว่าต่างส่วนทำงานร่วมกันอย่างถูกต้องนั้นยากขึ้น การนำการทดสอบหน่วยมาใช้ทำให้ป้องกันบั๊กที่ไม่คาดคิดจากการเปลี่ยนแปลงเล็กน้อยได้ง่ายขึ้นและช่วยรักษาเสถียรภาพของโปรแกรมโดยรวม2. วิธีการใช้ unittest เบื้องต้น
unittestพื้นฐานคือการสร้างคลาสที่สืบทอดจาก unittest.TestCase แล้วกำหนดเมธอดทดสอบภายในคลาสนั้น ในเมธอดทดสอบจะใช้เมธอด assertion เช่น assertEqual() เพื่อเปรียบเทียบผลลัพธ์ที่คาดหวังกับผลลัพธ์จริงตัวอย่างการทดสอบพื้นฐาน
โค้ดต่อไปนี้เป็นตัวอย่างง่าย ๆ ที่ทดสอบฟังก์ชันadd(a, b)import
# โค้ดที่ต้องทดสอบ
def add(a, b):
    return a + b
# คลาสทดสอบ
class TestAddFunction(unittest.TestCase):
    def test_add_integers(self):
        result = add(2, 3)
        self.assertEqual(result, 5)
if __name__ == '__main__':
    unittest.main()add() ทำงานอย่างถูกต้องหรือไม่ เมธอด assertEqual() ตรวจสอบว่าค่าที่คาดหวังและผลลัพธ์จริงเท่ากัน วิธีนี้ช่วยยืนยันว่าฟังก์ชันทำงานถูกต้องในหลายกรณีการขยายการทดสอบ
สามารถใช้เมธอดทดสอบหลาย ๆ ตัวเพื่อทดสอบการทำงานของฟังก์ชันกับอินพุตที่หลากหลาย เช่น การทดสอบจำนวนทศนิยมหรือการต่อสตริงdef test_add_floats(self):
    result = add(2.5, 3.5)
    self.assertAlmostEqual(result, 6.0, places=2)
def test_add_strings(self):
    result = add("Hello, ", "World!")
    self.assertEqual(result, "Hello, World!")3. วิธีการใช้ setUp() และ tearDown()
เพื่อให้ดำเนินการบางอย่างโดยอัตโนมัติก่อนและหลังการทดสอบ ให้ใช้เมธอดsetUp() และ tearDown() ซึ่งจะทำให้สามารถเตรียมการที่จำเป็นก่อนการรันเทสต์และทำความสะอาดหลังจากเทสต์เสร็จสิ้นได้ตัวอย่าง setUp()
setUp() เมธอดเป็นเมธอดที่เรียกใช้เสมอก่อนแต่ละเมธอดทดสอบ ทำให้สามารถรวมขั้นตอนการเริ่มต้นที่ใช้ร่วมกันได้def setUp(self):
    self.temp_value = 42ตัวอย่าง tearDown()
tearDown() เมธอดจะทำงานหลังจากแต่ละเมธอดทดสอบ เพื่อทำการทำความสะอาดหรือปล่อยทรัพยากร เช่น การตัดการเชื่อมต่อฐานข้อมูลหรือการลบไฟล์ชั่วคราวdef tearDown(self):
    self.temp_value = None4. การทดสอบความขึ้นอยู่ด้วยการใช้ Mock
เมื่อโค้ดที่ต้องการทดสอบพึ่งพาแหล่งข้อมูลภายนอก(ฐานข้อมูล、API เป็นต้น)ในกรณีที่พึ่งพานั้นถูกแทนที่ด้วย mock จะช่วยปรับปรุงความเร็วในการรันเทสต์และทำให้เทสต์สามารถคาดการณ์ได้ หากใช้โมดูลunittest.mock ของ Python ก็สามารถทำได้อย่างง่ายดายตัวอย่างการใช้ Mock
ในโค้ดต่อไปนี้ ฟังก์ชันที่ใช้เวลานานtime_consuming_function() ถูกแทนที่ด้วย mockfrom unittest.mock import patch
class TestAddFunction(unittest.TestCase):
    @patch('my_module.time_consuming_function')
    def test_add_with_mock(self, mock_func):
        mock_func.return_value = 0
        result = add(2, 3)
        self.assertEqual(result, 5)time_consuming_function ซึ่งช่วยลดเวลาในการทดสอบในขณะเดียวกันก็ได้ผลลัพธ์ที่แม่นยำ
5. การจัดการข้อยกเว้นและการอ้างอิงแบบกำหนดเอง
unittest ในสามารถทดสอบการจัดการข้อยกเว้นได้เช่นกัน ตัวอย่างเช่น เพื่อตรวจสอบว่าข้อยกเว้นเกิดขึ้นอย่างถูกต้องในสถานการณ์เฉพาะ ให้ใช้ assertRaises() เพื่อทำเช่นนั้นการทดสอบการจัดการข้อยกเว้น
ในตัวอย่างต่อไปนี้ จะตรวจสอบว่ามีการเกิดZeroDivisionErrordef test_divide_by_zero(self):
    with self.assertRaises(ZeroDivisionError):
        divide(1, 0)divide(1, 0) จะเกิด ZeroDivisionErrorการสร้างการอ้างอิงแบบกำหนดเอง
ในกรณีที่การอ้างอิงมาตรฐานไม่สามารถรองรับได้ สามารถสร้างเมธอดการอ้างอิงแบบกำหนดเองของคุณเองได้def assertIsPositive(self, value):
    self.assertTrue(value > 0, f'{value} is not positive')6. ฟีเจอร์การค้นหาเทสต์ของ unittest
การใช้ฟีเจอร์การค้นหาเทสต์ของunittest จะทำให้คุณสามารถค้นหาและรันไฟล์เทสต์ทั้งหมดในโปรเจกต์โดยอัตโนมัติ ฟีเจอร์นี้มีประโยชน์อย่างยิ่งโดยเฉพาะในโปรเจกต์ขนาดใหญ่วิธีใช้การค้นหาเทสต์
เพื่อรันการค้นหาเทสต์ ให้ใช้คำสั่งต่อไปนี้python -m unittest discovertest_*.py ทั้งหมดในไดเรกทอรีที่ระบุ หากต้องการระบุไฟล์หรือไดเรกทอรี ให้ใช้ตัวเลือกดังต่อไปนี้python -m unittest discover -s tests -p "test_*.py"
7. เคล็ดลับการเพิ่มประสิทธิภาพด้วย unittest
หากความเร็วในการรันเทสต์ช้า ประสิทธิภาพการพัฒนาจะลดลง ที่นี่เราจะแนะนำเคล็ดลับบางอย่างเพื่อปรับปรุงประสิทธิภาพของเทสต์โดยใช้unittest。เพิ่มประสิทธิภาพไฟล์ I/O
เทสต์ที่ต้องอ่านเขียนไฟล์สามารถเร่งความเร็วได้โดยประมวลผลในหน่วยความจำ ใช้StringIO เพื่อสร้างอ็อบเจ็กต์ที่ทำหน้าที่เหมือนไฟล์ในหน่วยความจำ ทำให้หลีกเลี่ยงการทำ I/O กับดิสก์。from io import StringIO
class TestFileOperations(unittest.TestCase):
    def test_write_to_memory(self):
        output = StringIO()
        output.write('Hello, World!')
        self.assertEqual(output.getvalue(), 'Hello, World!')ใช้ Mock
เพื่อจำกัดการเข้าถึงทรัพยากรภายนอก เราสามารถใช้ Mock เพื่อเร่งความเร็วของเทสต์ได้ ซึ่งช่วยหลีกเลี่ยงความล่าช้าจากเครือข่ายฐานข้อมูลและลดเวลาการรันเทสต์ ตัวอย่างต่อไปนี้จะแทนการเรียก API ด้วย Mock。from unittest.mock import MagicMock
class TestApiCall(unittest.TestCase):
    def test_api_response(self):
        mock_api = MagicMock(return_value={'status': 'success'})
        response = mock_api()
        self.assertEqual(response['status'], 'success')8. สรุปและขั้นตอนต่อไป
ในบทความนี้ เราได้อธิบายอย่างกว้างขวางตั้งแต่พื้นฐานของการทดสอบหน่วยด้วยunittest ของ Python การใช้การตั้งค่าและการทำความสะอาด การทดสอบความขึ้นอยู่ด้วย mock ไปจนถึงเทคนิคการปรับปรุงประสิทธิภาพของการทดสอบสรุปประเด็นสำคัญ
- วิธีการใช้พื้นฐาน: สืบทอดจาก unittest.TestCaseและใช้เมธอด assertion เพื่อสร้างการทดสอบ
- setUp() / tearDown(): การจัดการกระบวนการทั่วไปก่อนและหลังการทดสอบช่วยเพิ่มการนำโค้ดกลับมาใช้ใหม่และความอ่านง่ายของโค้ด
- การใช้ mock: สามารถทดสอบฟังก์ชันโดยไม่ต้องพึ่งพาแหล่งข้อมูลภายนอก ทำให้ประสิทธิภาพของการทดสอบเพิ่มขึ้นอย่างมาก
- การค้นพบการทดสอบ (Test Discovery): ฟีเจอร์ที่สะดวกช่วยให้การจัดการการทดสอบในโครงการขนาดใหญ่ง่ายขึ้น
- เทคนิคการปรับปรุงประสิทธิภาพ: การประมวลผลในหน่วยความจำและการใช้ mock สามารถลดเวลาการรันของการทดสอบได้
ขั้นตอนต่อไป
เมื่อคุณเชี่ยวชาญพื้นฐานของunittest แล้ว ลองท้าทายวิธีการทดสอบขั้นสูงต่อไป เช่น การทดสอบแบบพารามิเตอร์ที่สามารถทดสอบข้อมูลหลายชุดพร้อมกัน หรือใช้เครื่องมือ coverage เพื่อตรวจสอบขอบเขตการทดสอบของโค้ด ซึ่งช่วยเสริมกลยุทธ์การทดสอบของโครงการทั้งหมด นอกจากนี้ การมองหาเฟรมเวิร์กการทดสอบอื่น ๆ เช่น pytest ก็เป็นทางเลือกที่ดีเพื่อขยายตัวเลือกตามการใช้งาน
การทดสอบเป็นส่วนสำคัญของการพัฒนา เพื่อค้นหา bug ตั้งแต่เนิ่นๆ และรักษาคุณภาพของโค้ด ควรนำการทดสอบเข้ามาใช้โดยกระตือรือร้น
 
 



