Unit Test เสียหน่อย

คิดว่าหลาย ๆ คนที่ทำงานสายโปรแกรมมิ่งน่าจะคุ้นเคยกับคำว่า Unit Testing กันบ้างไม่มากก็น้อย แต่ผมว่าคงมีบางคนที่ถึงจะทำ Unit Test ทุกวันก็ไม่รู้ว่ามันหมายความว่าอะไรกันแน่

คำว่า Unit Test ก็คือการทดสอบ “หน่วย” ของโปรแกรม — แปลตรงตัวดีเนอะ (ฮา) คำว่าหน่วยของโปรแกรมเนี่ยจริง ๆ ก็ไม่มีคำจำกัดความตายตัวว่ามันย่อยขนาดไหน แต่โดยทั่วไปแล้วเมื่อพูดถึง Procedural Programming แล้วมักจะหมายถึงระดับฟังก์ชั่น หรือถ้าพูดถึง  OOP แล้วก็มักจะเป็นระดับเมธอด

การทำ Unit Test  เนี่ย อย่างที่บอกว่าทำกันที่ระดับฟังก์ชั่น หรือเมธอด สิ่งที่ทำจริงก็ไม่มีอะไรมาก เราก็แค่ค่อย ๆ ป้อน Input ที่เป็นไปได้ทั้งหมดทีละตัวๆ แล้วดูว่า Output ที่ได้นั้นทำงานถูกต้องหรือไม่ ทำไปทีละตัวจนกว่าจะครบ แค่นี้เอง

แต่ว่าไอ้ “แค่นี้เอง” ที่ว่าพอเอาเข้าจริง ๆ มันก็เยอะ ถึงเยอะมาก ๆ บางครั้งบางคราวเราจึงพบเห็นการทดสอบแบบ … เอาแค่ Input ชุดเล็ก ๆ สุ่ม ๆ เอาแล้วดูผลลัพท์ คือถ้ามันมีจำนวนเคสที่เป็นไปได้เป็นล้าน ๆ เคส (เอ้า ไม่แปลกนะ สมมติผมเทสต์ฟังกั่น pow(int)  เนี่ย ถ้าจะทำให้ครบต้องทำถึงสี่พันล้านเคสทีเดียว) ผมว่าจะสุ่มมันก็โอเค แต่ถ้าจำนวนเคสที่เป็นไปได้มันไม่ได้เยอะมาก อาจจะสักต่ำกว่า 100 เคสขึ้นไปก็ควรจะทำ Unit Test ให้ครบทุกเคส ถึงแม้ว่าการมันจะกินแรงงานมากก็เถอะ

แต่พูดจริง ๆ นะ พอต้องทำ Unit Test เนี่ยพอเกินสัก 10 เคสก็หน้ามืดแล้วครับ ยิ่งพอต้องทำเอกสารกำกับอีกเนี่ยขอบอกว่ามึนโคตร ๆ

ที่แย่กว่านั้นผมเจอว่าบางที่ การทำ Unit Test  มันเลยเถิดและครอบคลุมไปฟังก์ชั่นอื่น บางครั้งเลยจนถึงขั้นไปอีกโปรแกรมเลยก็มี (อันนี้เจอประจำ 555) ซึ่งการเทสต์แบบครอบจักรวาลแบบนี้นอกจากจะใช้เวลามาก และทำให้การทดสอบทำได้ไม่ทั่วถึงแล้ว ยังมีโอกาสที่จะถูกความผิดพลาดของฟังก์ชั่นอื่นที่เราไม่ได้ไปเกี่ยวยุ่งด้วยเนี่ยมาทำให้ผลการทดสอบบิดเบือนไปด้วย (อันนี้ประสพการณ์ตรงครับ) ที่จริงหน้าที่ตรงนี้เป็นของการทดสอบแบบอื่น (เช่น Functional Testing ที่ทดสอบว่าความสามารถของโปรแกรมในด้านใดด้านหนึ่งนั้นทำงานถูกต้อง และ Integration Testing ที่ทดสอบว่าการเอาฟังก์ชั่นนี้ไปใช้งานกับฟังก์ชั่นอื่นนั้นทำงานได้ถูกต้อง มักจะทำเวลาที่เขียนฟังก์ชั่นขึ้นมาใหม่หรือมีการแก้ไขแบบยกเครื่อง) ซึ่งก็สำคัญเหมือนกัน แต่ไม่ควรเหมามาเป็น Unit Test ครับ

ในปัจจุบันการใช้ Unit Test Framework เข้ามามีบทบาทสำคัญกับชีวิตนักพัฒนาค่อนข้างมาก เพราะมันทำให้การทำเทสต์ 100 เคสกับฟังก์ชั่นฟังก์ชั่นเดียวมันสะดวกมาก แถมพอจะทำเทสต์ก็แค่รัน Test Suite ซึ่งทำให้การทำ Unit Test นั้นสามารถทำซ้ำได้ ที่จริงใน Continuous Integration (CI หรือที่ผมเรียกว่าการบูรณาการต่อเนื่อง) Unit Test ทั้งชุดจะถูกทำทุกครั้งหลังจากที่ทำ Daily Build และจะมี Report ออกมาทันทีว่ามีการทดสอบที่ไม่ผ่านที่ฟังก์ชั่นไหนบ้างครับ

เอ้อ … ยังไม่ได้อธิบายเรื่อง Unit Test Framwork เลยว่ามันคืออะไร เจ้านี่เป็นเฟรมเวิร์สำหรับเขียนโปรแกรมที่ใช้สำหรับทดสอบคลาสหรือฟังก์ชั่น ตัวมันเองจะเก็บเอาค่า input และ output ที่คาดหวังเอาไว้ของแต่ละฟังก์ชั่น และพอเรารันมันจะค่อยทดสอบทีละเคสจนครบ และมันก็จะรายงานว่ามีเคสไหนที่ไม่ผ่านบ้าง

Unit Test Framework ส่วนใหญ่จะไม่สามารถทดสอบส่วนของ User Interface ได้ คือป้อนอินพุตก็พอได้ (แต่ลำบาก) แต่ไอ้ตอนไปดูว่า output ถูกต้องมั้ยเนี่ยมันต้องใช้ Image Processing ซึ่งผมก็นึกไม่ออกว่าจะเขียนเป็นเทสต์เคสด้วยโปรแกรมยังไง ดังนั้นการทำ Unit Test ด้วยมือก็ยังมีความสำคัญอยู่ล่ะครับ ส่วนพวกโปรแกรมที่ต้องอ้างอิงถึง input ที่มาจากแหล่งอื่น เช่นพวกไฟล์ หรือ service ก็จำเป็นจะต้องใช้  mock up data ช่วย ก็มี Framework อีกตัวที่มาเกี่ยวข้องเหมือนกันครับ เรียกว่า Mocking Framework

UTF ที่ดัง ๆ ก็จะเป็นตระกูล xUnit  (แทนตัวหน้าด้วยตัวย่อของภาษาต่าง ๆ เอาครับ)ลองศึกษาเพิ่มเติมกันได้

สุดท้ายนี้ก่อนจากอยากแนะนำว่า เวลาจะพัฒนาโปรแกรมควรจะพัฒนาตัว Test Program ควบคู่กันไปด้วย (โดยใช้ Unit Test Framework) เพราะถ้าทำช้าเทสเคสมันจะเยอะมากแล้วเราจะพาลขี้เกียจทำครับ ที่จริงมีคนแนะนำให้เขียน  Test Program ก่อนที่จะเขียนตัวโปรแกรมด้วยซ้ำ อันนี้ก็ลองดูกันครับ

ใส่ความเห็น

อีเมลของคุณจะไม่แสดงให้คนอื่นเห็น ช่องข้อมูลจำเป็นถูกทำเครื่องหมาย *

This site uses Akismet to reduce spam. Learn how your comment data is processed.