หลังจากพักสำหรับการเขียน Blog ของการเรียน Python มานาน เพื่อไปเตรียมสอบ MCSD ตอนนี้ได้เวลามาอัพ Blog ต่อแล้วครับ สำหรับใน Week 4 เน้นไป 5 เรื่อง ดังนี้
การทดสอบ(Testing)
📚 ที่มาของ ฺBug มันมีที่มาจากแมลงจริงๆ ที่ดันเข้าไปติดในคอมพิวเตอร์สมัยก่อนครับ ตอนแรกDev เองนึกว่า Code ผิด แต่ป่าวมีแมลงไปติดที่วงจรซะงั้น

📚 ในเรื่องนี้ผู้สอน เค้าได้นำเสนอแนวคิด Defensive Programming ครับ

❓ เมื่อไหร่ถึง Test หละ
- ทำงานเสร็จระดับนึง
- Code Complile ผ่าน ไม่มี Syntax Error
- มี Test Case คือ ชุดทดสอบที่มีการกำหนดข้อมูลนำเข้า(Input) และผลลัพธ์ที่ได้(Exprected Result) แล้ว
📚 ทุกอย่างมันอยู่ในมือเราแล้ว ทำอย่างไรให้มัน Testing และ Debug ง่ายหละ
- Decomposition - แบ่งให้มันเป็นชิ้นเล็กที่ทุกสุดเท่าที่จะทำได้สิ ^__^
- Document Constraints - ผมมองว่าเป็น Test Case
- Document Assumptions - ตอนนี้ทำไมถึงใช้ Algorithm นี้หละ แต่ปัญหาหลักที่เจอ คือ แม้แต่พระเจ้า ท่านไม่รู้หรอกว่า สิ่งที่เราทำไม เมื่อเดือนที่แล้ว เพราะอะไร จดไว้บาก็ดีครับ
📚 Class of Tests
- Unit Testing - Test ในจุดที่เล็กที่สุด ยิ่งแรกแบ่งส่วนของงานได้เล็กลงเท่าไหร่ เราสามารถเจาะเข้าไปได้ ให้มันได้ละเอียดมากขึ้นครับ
- Regression Testing - Test ซ้ำเพิ่มจากตัว Unit Test เพื่อให้มั่นใจว่า แก้ ฺBug อันใหม่ไปแล้ว Bug เก่ามันไม่มาหลอกหลอน
- Integration Testing - Test โดยเอาหลายส่วนมาทำงานร่วมกัน
Testing Approach
🗳️ Black Box Testing - โยน Input เข้าไป ดูผลลัพธ์ที่ออกมา
- จุดเด่น - เราสามารถเอา Test Case มา Reused ได้ แม้ว่าไส้ข้างใน มีการปรับแก้ไข และป้องกัน Dev ที่ทำลำเอียง
- จุดด้อย - คน Test เข้าใจสิ่งที่ทำพอสมควรเลย อาจจะเป็น Business Domain เพื่อกำหนด Test Case ได้อย่างเหมาะสม
- การกำหนด Test Case สำหรับ Black Box คือ เรื่อง Boundary Condition เอาง่ายพวกขอบเขต เช่น
- Min/Max
- List เป็น null
- List ไม่มีข้อมูล เป็นต้น
🥛Glass Box Testing - เรียกยังไงดี บอกว่ามันดีจากภายใน เพราะ การ Test เราต้อง Design Test Cases มาจาก Code ที่เขียน
- จุดที่ Code ที่ต้องสนใจมีหลายจุด เช่น
- เงื่อนไข - IF / Switch
- การทำซ้ำ - For Loop / While Loop เป็นต้น
- จุดเด่น - ทดสอบได้ลึก และครอบคลุมกว่า Black Box สิ่งที่บอกว่าครบคลุมนั้น เราต้อง Test ทุกทางที่เป็นไปได้ เช่น IF - ELSE มี 2 สองให้ ทดสอบแล้ว
- จุดด้อย - ใช้เวลานาน อาจจะมี Test หลุด ไม่ครบทุกเส้นทางได้
- การกำหนด Test Case อย่าลืมเรื่อง Boundary Condition
การติดตามพฤติกรรมของโปรแกรม (Debug)
🐞Runtime Bug
- Overt(บึ้มไปเลย) กับ Covert(ทำงานได้ ผลลัพธ์ผิด)
- Persistent(มี Step การบึ้มที่แน่นนอน) กับ Intermittent(อยู่ๆ ก็พัง)
นิยามของคำว่า Debug = การติดตามพฤติกรรมของโปรแกรม อันนี้ผมเขียนขึ้นมาเองนะ จริงๆ การ Debug มันเหมือนว่าตัว Dev เอากำลังสวมบทบาทเป็นคุณหมอวินิจฉัย และผ่าตัดเอาสิ่งที่ผิดปกติออกจากโปรแกรมที่เขียนขึ้นครับ
🐞 แนวทาง Debug เพื่อจับ Bug
- แบบง่าย Runtime มันด่าเราได้ ว่า Error อะไร อันนี้ดูได้ง่าย
- แบบยาก มันทำงานได้ แต่ค่าผิด L0gical Error
- ต้องรู้ว่า Code ของเราทำอะไร
- ถ้ามันไม่บอก Print มันออกมา
- พยายามตัดปัญหาได้ได้แบบ Bi-Section Search ตัดขอบเขตของปัญหาลงเรื่อยๆ

Note: นำแนวคิดของ Defense Programming มาใช้ แต่ถ้าเหนื่อยไปก็พักบ้าง บางครั้งเราอาจจะเจอปัญหาแบบเส้นผมบังภูเขานะ
ในเรื่องนี้ผมตลกกับคนสอนนะ แกบอกว่า Dev มักพูดคุณกับตุ๊กตาเป็ด พอกลับมามองดุตัวเอง เอ๊ะ เราพูด หรือป่าวนะ 5555
การจัดการกับข้อผิดพลาด(Exception)
🚏ทำไมต้องมี Exception ?
เราอยากรู้ว่าโปรแกรม มันบอกอะไรไหม บึ้มเงียบๆ (Fail silently) มันไม่ค่อยดีนะ แล้วเราสามารถช่วยจัดการไหม เช่น กรอกเลขผิด ปล่อยยาวไปจนผิดไปอีกหลาย Process ทั้งที่จริงๆ เราดักได้ตั้งแต่แรก
🚏Exception มีอะไรบ้าง เช่น

Exception มีอีกหลายแบบนะ เช่น ZeroDivisionError, IOError, AttributeError เป็นต้น
🚏Pattern ของการดัก Exception ตาม Code เลยครับ
data = [] file_name = input("Provide a name of a file of data ") try: # ลอง Execute Code ที่เลี่ยงเกิดข้อผิดพลาด ในที่นี้ลองเปิดไฟล์ บางครั้งไฟล์อาจจะถูกใช้ หรือ ไม่มีอยู่จริง fh = open(file_name, 'r') except IOError: # ดัก Exception ที่อาจจะเกิด print('cannot open', file_name) else: # ถ้าไม่มี Error ก็ทำงานต่อไป for new in fh: if new != '\n': addIt = new[:-1].split(',') # remove trailing \n data.append(addIt) finally: # ไม่ว่าจะ Error หรือทำสำเร็จ ก็ต้องทำ Section นี้เสมอ fh.close() # close file even if fail
- try - ลอง Execute Code ที่เลี่ยงเกิดข้อผิดพลาด
- except - ดัก Exception ที่อาจจะเกิด ถ้ามีหลายตัวเรียงความสำคัญจากเล็ก ไป ใหญ่ เช่น
# some code here except ValueError: print("Could not convert to a number.”) except ZeroDivisionError: print("Can't divide by zero”) except: print("Something went very wrong.”) # some code here
- else - ถ้าไม่มี Error ก็ทำงานต่อไป
- finally - ไม่ว่าจะ Error หรือทำสำเร็จ ก็ต้องทำ Section นี้เสมอ
🚏อยากโยน Exception เอา ทำได้นะ Pattern ดังนี้เลย

การยืนยัน(Assertions)
✅ มันต่างกับ Exception อย่างไร?
- Assertions ป้องกันก่อน Execute
- Exception แสดงข้อผิดพลาดหลัง Execute
✅ ตัว Assertion มันช่วยเรื่อง Defensive Programming ด้วยนะ ในสถานการณ์นี้ ถ้ามีอะไรผิดพลาด มีการ Raise Exception ออกมา
- ก่อนเข้า Pre - Process : check inputs
- ระหว่าง Process : ให้หยุดการทำงาน(Execution halts)ถ้าค่ามันผิดแปลกไป
- หลังจบจาก Post-Process : check outputs ก่อนคืนค่าออกมา
✅ ตัวอย่าง Assertions
def avg(grades): assert not len(grades) == 0, # no grades data //ตรวจว่า input มีข้อมูลที่ส่งเข้ามาจริงไหม ? return sum(grades)/len(grades)
✅ ตัว Assertion เน้นเอาไปวางใน Unit Test ด้วย
Blog ยาวเลยครับ สำหรับเรื่องนี้ สะสมที่ดองมานานหลาย Week ครับ และสุดท้ายของแถม Quote อันนึง
"Source Code always tells the truth"
PingkungA
Discover more from naiwaen@DebuggingSoft
Subscribe to get the latest posts sent to your email.