ทดสอบและจัดการข้อผิดพลาด
การทดสอบโปรแกรมเป็นขั้นตอนสำคัญในการพัฒนาและบำรุงรักษาโปรแกรม ช่วยให้มั่นใจว่าโค้ดที่เขียนขึ้นทำงานตามที่คาดหวังและไม่มีข้อผิดพลาดที่อาจส่งผลกระทบต่อการทำงานของโปรแกรม การใช้เครื่องมือทดสอบที่เหมาะสมจะช่วยให้การทดสอบเป็นไปอย่างรวดเร็วและมีประสิทธิภาพมากยิ่งขึ้นใน Python มีเครื่องมือหลากหลายที่สามารถใช้ในการทดสอบ เช่น unittest ซึ่งเป็นโมดูลพื้นฐานสำหรับการเขียนและรันการทดสอบฟังก์ชัน, pytest ที่มีความยืดหยุ่นสูง, และ doctest ที่ช่วยในการทดสอบภายในเอกสาร นอกจากนี้ การจัดการข้อผิดพลาด (Error Handling) ยังเป็นสิ่งที่สำคัญไม่แพ้กัน เพื่อให้โปรแกรมสามารถจัดการกับสถานการณ์ที่ไม่คาดคิดได้อย่างมีประสิทธิภาพ และนำไปสู่การสร้างโปรแกรมที่มีความเสถียรและน่าเชื่อถือมากยิ่งขึ้น
การจัดการข้อผิดพลาดเป็นสิ่งที่ต้องเข้าใจอย่างลึกซึ้งก่อนที่จะเริ่มสร้างการทดสอบ การใช้โครงสร้าง try-except ช่วยให้โปรแกรมสามารถจัดการกับข้อผิดพลาดได้อย่างมีประสิทธิภาพ และไม่ทำให้โปรแกรมหยุดทำงานกะทันหันเมื่อพบข้อผิดพลาด
try ในบล็อกนี้ สามารถเขียนโค้ดที่คาดว่าอาจเกิดข้อผิดพลาดได้ หากโค้ดในบล็อก try ทำงานสำเร็จ
จะข้ามบล็อก except และทำงานต่อไปในโปรแกรม ถ้าหากเกิดข้อผิดพลาดในบล็อก try
จะมีการหยุดการทำงานในบล็อกนี้ทันที และไปที่บล็อก except
except บล็อกนี้จะทำงานเมื่อเกิดข้อผิดพลาดในบล็อก try โดยสามารถกำหนดประเภทของข้อผิดพลาด
ที่ต้องการได้ และสามารถจัดการกับข้อผิดพลาดได้ในบล็อกนี้ เช่น การพิมพ์ข้อความแจ้งเตือน
หรือการแก้ไขปัญหา
1. SyntaxError ข้อผิดพลาดที่เกิดจากไวยากรณ์ของโค้ดไม่ถูกต้อง เช่น การลืมใส่วงเล็บหรือเครื่องหมายจุลภาค
2. TypeError เกิดขึ้นเมื่อพยายามทำงานกับประเภทข้อมูลที่ไม่เข้ากัน เช่น การรวมสตริงกับจำนวนเต็ม
3. ValueError เกิดขึ้นเมื่อมีการส่งค่าไม่ถูกต้องให้กับฟังก์ชัน เช่น การแปลงข้อมูลที่ไม่สามารถแปลงได้
4. IndexError เกิดขึ้นเมื่อพยายามเข้าถึงดัชนีที่อยู่นอกช่วงของรายการ (list) หรือสตริง
5. KeyError เกิดขึ้นเมื่อพยายามเข้าถึงคีย์ที่ไม่มีอยู่ในดิกชันนารี
6. ZeroDivisionError เกิดขึ้นเมื่อพยายามหารด้วยศูนย์
7. AttributeError เกิดขึ้นเมื่อพยายามเข้าถึงแอตทริบิวต์ที่ไม่มีอยู่ในอ็อบเจ็กต์
8. ImportError เกิดขึ้นเมื่อไม่สามารถนำเข้าโมดูลหรือแพ็กเกจที่ต้องการได้
ใน Python สามารถจัดการกับข้อผิดพลาดเหล่านี้ได้ในบล็อก except โดยสามารถระบุชนิดของข้อผิดพลาดที่ต้องการจัดการได้
💻 ตัวอย่าง การจัดการข้อผิดพลาดที่เฉพาะเจาะจง
การจัดการข้อผิดพลาดที่เฉพาะเจาะจงจะช่วยให้โปรแกรมสามารถทำงานต่อไปได้อย่างมีประสิทธิภาพและแสดงข้อความที่ชัดเจนเมื่อเกิดข้อผิดพลาดขึ้น การทำเช่นนี้จะช่วยในการดีบักโค้ดและทำให้โปรแกรมมีความเสถียรมากขึ้น
💻 ตัวอย่าง การใช้ try-except จัดการกับข้อผิดพลาดโปรแกรมสำหรับการหารตัวเลข
โดยจัดการกับข้อผิดพลาดที่ผู้ใช้อาจไม่ใส่ตัวเลข ทั้งยังให้ความสะดวกในการเลือกว่าจะทำงานต่อหรือหยุดทำงาน
บรรทัดที่ 1 เริ่มลูปไม่สิ้นสุด ทำให้โปรแกรมสามารถทำงานได้เรื่อย ๆ จนกว่าจะรับค่า “n”
บรรทัดที่ 2 เริ่มบล็อก try เพื่อระบุโค้ดที่อาจเกิดข้อผิดพลาดได้
บรรทัดที่ 3-4 รับค่าตัวตั้งและตัวหารจากผู้ใช้แล้วแปลงเป็นจำนวนเต็ม
บรรทัดที่ 5 ทำการหารตัวตั้งด้วยตัวหารและเก็บผลลัพธ์ไว้ในตัวแปร result
บรรทัดที่ 6 ถ้าเกิดข้อผิดพลาดจากการป้อนค่าที่ไม่ใช่ตัวเลข โปรแกรมจะเข้าสู่บรรทัดที่ 7
บรรทัดที่ 7 แสดงข้อความแจ้งผู้ใช้ว่าให้ป้อนตัวเลขเท่านั้น
บรรทัดที่ 8 ถ้าผู้ใช้ป้อนค่า 0 เป็นตัวหาร จะเกิดข้อผิดพลาด ZeroDivisionError โปรแกรมจะเข้าสู่บรรทัดที่ 9
บรรทัดที่ 9 แสดงข้อความแจ้งว่าการหารด้วยศูนย์ไม่สามารถทำได้
บรรทัดที่ 10 ถ้าไม่มีข้อผิดพลาดเกิดขึ้น โปรแกรมจะเข้าสู่บรรทัดที่ 11
บรรทัดที่ 11 แสดงผลลัพธ์ของการหารที่ได้เมื่อไม่มีข้อผิดพลาด
บรรทัดที่ 14 เริ่มลูปใหม่เพื่อรับการตอบสนองจากผู้ใช้ว่าจะทำงานต่อหรือไม่
บรรทัดที่ 15 รับการตอบสนองจากผู้ใช้โดยให้ป้อน 'y' หรือ 'n' แล้วทำการลบช่องว่างและแปลงเป็นตัวพิมพ์เล็ก
บรรทัดที่ 16 ถ้าผู้ใช้ตอบ 'y', โปรแกรมจะเข้าสู่บรรทัดที่ 17
บรรทัดที่ 17 ออกจากลูปนี้เพื่อกลับไปที่การหาร
บรรทัดที่ 18 ถ้าผู้ใช้ตอบ 'n', โปรแกรมจะเข้าสู่บรรทัดที่ 19 และบรรทัดที่ 20
บรรทัดที่ 19 แสดงข้อความขอบคุณผู้ใช้ที่ใช้งานโปรแกรม.
บรรทัดที่ 20 หยุดโปรแกรม
บรรทัดที่ 21 ถ้าผู้ใช้ป้อนค่าที่ไม่ใช่ 'y' หรือ 'n', โปรแกรมจะเข้าสู่บรรทัดที่ 22
บรรทัดที่ 22 แจ้งผู้ใช้ให้ป้อนค่าใหม่ที่ถูกต้อง
unittest เป็นโมดูลที่ใช้ในการเขียนและเรียกใช้การทดสอบอัตโนมัติ (automated tests) สำหรับโค้ดที่เขียนขึ้น โครงสร้างพื้นฐานของการใช้งาน unittest ประกอบด้วยคลาสและเมธอดที่กำหนดไว้เพื่อทดสอบฟังก์ชันต่าง ๆ
1. นำเข้าโมดูล unittest เพื่อให้สามารถใช้ฟังก์ชันและคลาสต่าง ๆ ในการทดสอบได้
2. สร้างคลาสสำหรับการทดสอบ สร้างคลาสที่สืบทอดจาก unittest.TestCase ซึ่งเป็นที่เก็บเมธอดการทดสอบ
3. เขียนเมธอดการทดสอบ เมธอดการทดสอบต้องมีชื่อเริ่มต้นด้วย test_ เพื่อให้ unittest รู้ว่าต้องเรียกใช้เมธอดนี้
4. ใช้ assertions methods เพื่อเปรียบเทียบผลลัพธ์ที่คาดหวังกับผลลัพธ์ที่ได้
5. เรียกใช้การทดสอบเรียกใช้การทดสอบโดยใช้ unittest.main() เพื่อรันการทดสอบเมื่อไฟล์ถูกเรียกใช้โดยตรง
คือ เมธอดสำหรับการตรวจสอบผลลัพธ์ที่ใช้ในการตรวจสอบความถูกต้องของเงื่อนไขหรือค่าที่คาดหวังในการทำงานของโปรแกรม โดยทั่วไป ถ้าเงื่อนไขเป็นจริงโปรแกรมจะทำงานต่อไปตามปกติ แต่ถ้าเงื่อนไขไม่เป็นจริง จะทำให้เกิดข้อผิดพลาด (assertion error) เพื่อบอกว่ามีบางอย่างไม่ถูกต้องในโค้ด ตัวอย่างที่ใช้บ่อย เช่น
1. assertEqual(a, b): ตรวจสอบว่า a เท่ากับ b
2. assertTrue(x): ตรวจสอบว่า x เป็น True
3. assertFalse(x): ตรวจสอบว่า x เป็น False
4. assertRaises(error, func, *args): ตรวจสอบว่าฟังก์ชัน func เกิดข้อผิดพลาด error เมื่อเรียกใช้
💻 ตัวอย่าง การทดสอบด้วย unittest เพื่อทดสอบฟังก์ชันสำหรับบวกตัวเลขสองจำนวน
บรรทัดที่ 1 นำเข้าโมดูล unittest เพื่อใช้ในการสร้างการทดสอบอัตโนมัติ
บรรทัดที่ 4 นิยามฟังก์ชัน add() ซึ่งรับค่า 2 ตัวเป็นพารามิเตอร์ a และ b
บรรทัดที่ 5 ฟังก์ชันทำการบวกค่าของ a และ b และส่งคืนผลลัพธ์.
บรรทัดที่ 8 สร้างคลาส TestMathFunctions ที่สืบทอดจาก unittest.TestCase เพื่อใช้ในการเก็บเมธอดสำหรับการทดสอบ
บรรทัดที่ 11 นิยามเมธอด test_add() เพื่อใช้ทดสอบฟังก์ชัน add()
บรรทัดที่ 13 ทดสอบว่าผลลัพธ์ของการเรียก add(1, 2) จะต้องเป็น 3 ถ้าผลลัพธ์ไม่ใช่ 3 การทดสอบจะล้มเหลว
บรรทัดที่ 14 ทดสอบว่าผลลัพธ์ของการเรียก add(-1, 1) จะต้องเป็น 0 ถ้าผลลัพธ์ไม่ใช่ 0 การทดสอบจะล้มเหลว
บรรทัดที่ 15 ทดสอบว่าผลลัพธ์ของการเรียก add(0, 0) จะต้องเป็น 0 ถ้าผลลัพธ์ไม่ใช่ 0 การทดสอบจะล้มเหลว
บรรทัดที่ 18 ตรวจสอบว่าถ้าไฟล์นี้ถูกเรียกใช้โดยตรง (ไม่ใช่การนำเข้า) โค้ดในบรรทัดที่ 19 จะถูกดำเนินการ
บรรทัดที่ 19 เรียกใช้การทดสอบทั้งหมดในคลาสที่สืบทอดจาก unittest.TestCase ซึ่งในกรณีนี้คือ TestMathFunctions
การจัดการข้อผิดพลาด (Error Handling) และการทดสอบด้วย unittest เป็นเพียงจุดเริ่มต้นของการทดสอบและจัดการข้อผิดพลาด ในอนาคตนักศึกษาสามารถศึกษาเพิ่มเติมเกี่ยวกับเครื่องมือและแนวทางการทดสอบที่ซับซ้อนยิ่งขึ้น เช่น การทดสอบด้วย pytest ที่มีความยืดหยุ่นและสะดวกสบายมากกว่า การทดสอบเอกสารด้วย doctest เพื่อให้แน่ใจว่าตัวอย่างในเอกสารทำงานได้ตามที่ระบุ และการจำลองวัตถุและฟังก์ชันด้วย mock เพื่อช่วยในการทดสอบส่วนที่มีการพึ่งพาแหล่งข้อมูลภายนอก การพัฒนาทักษะเหล่านี้จะช่วยให้สามารถเขียนโปรแกรมที่มีคุณภาพสูงขึ้นและมีความน่าเชื่อถือได้ดียิ่งขึ้น ส่งผลให้สามารถรับมือกับความท้าทายใหม่ ๆ ในการพัฒนาซอฟต์แวร์ในอนาคตได้อย่างมีประสิทธิภาพ