สำหรับนักพัฒนาที่เขียน test หรือชุดการทดสอบ นะ !!
มาดูกันว่า ชุดการทดสอบมันส่งกลิ่นแปลก ๆ บ้างหรือไม่ ?

ปกติ code ที่นักพัฒนาสร้างขึ้นมา
มักจะมีสิ่งแปลก ๆ
มักจะส่งกลิ่น หรือ ส่งสัญญาณของปัญหาออกมา
ซึ่งเราเรียกว่า Code Smell

ปัญหามันไม่ใช่ Code Smell เพียงอย่างเดียว
แต่ ….
มันมีอย่างอื่นอีกเช่น
เรารู้หรือไม่ว่าสิ่งเหล่านั้นมันคือ Code Smell !!
ถ้าพูดง่าย ๆ คือ
เรามีจมูกที่ดีหรือไม่
เรามีสายตาที่ดีหรือไม่
เพื่อทำให้ได้กลิ่น ให้มองเห็น Code Smell หรือสิ่งที่ผิดปกติหรือไม่ ?
นั่นคือสิ่งที่นักพัฒนาต้องสร้างและปรับปรุงความสามารถขึ้นมา

สำหรับการทดสอบก็เช่นกัน
มาเริ่มกันเลยกับ Test/Unit Test Smell
ว่ามีปัญหาอะไร อย่างไรกันบ้าง ที่บ่งบอกว่าจะทำให้เกิดปัญหาขึ้นมาได้

ชุดการทดสอบมันเขียนยากนะ ต้องใช้เวลาเพิ่ม

เป็นปัญหาแรก ๆ ของการเขียนชุดการทดสอบเลย
ทั้งฝั่งนักพัฒนาและหัวหน้า รวมไปจนถึงฝ่าย management
อะไรที่ไม่เคยทำ หรือ ทำไม่เป็น มักจะบอกว่า
มันยาก ทำไม่ได้หรอก
แต่ถ้าต้องทำอาจจะใช้เวลาเยอะมากขึ้น

ประเด็นคือ เราเรียนรู้หรือยัง ?
ประเด็นคือ เราเคยลองทำหรือยัง และทำอย่างถูกต้องหรือไม่ ?

ยิ่งถ้าไปเขียนชุดการทดสอบกับระบบที่มีอยู่แล้ว
ยิ่งมีความยากขึ้นไปอีก
เนื่องจากระบบที่ไม่ได้คิดเรื่องของการทดสอบมาก่อน จะลำบากและยากมาก ๆ
อาจทำให้หมดกำลังใจไปได้เลย

ดังนั้น ถ้าเขียนชุดการทดสอบแล้วมันยาก
สิ่งที่ต้องมองคือ code ที่เรากำลังเผชิญอยู่มันมีปัญหาหรือไม่ ?

ชุดการทดสอบมาก หรือ ละเอียดจนเกินไป

เขียนชุดการทดสอบที่ว่าเหนื่อยและยากแล้ว
เขียนชุดการทดสอบมากจนเกินไปยิ่งเหนื่อยกว่ามาก !!
แต่ถ้าไม่เขียนมาก ๆ จะไม่รู้ว่าอะไรควรเขียนหรือไม่ควรเขียน !!

ยกตัวอย่างเช่นบรรดา private method ต่าง ๆ
ในช่วงเริ่มต้นมักจะเขียนเพื่อทดสอบ private method เหล่านี้ให้ครบ
จากนั้นก็ทำการทดสอบ method ที่เรียก private method นี้อีกรอบ
ซึ่งทำให้การทดสอบซ้ำจำนวนมากของ private method (Duplication test)

คำถามคือ เราควรทดสอบทั้งสอง method เลยหรือไม่ ?
ลองถามใจดูนะ

การทดสอบควรเน้นพฤติกรรมให้มากกว่าลงรายละเอียด
เพื่อช่วยลดผลกระทบของชุดการทดสอบจากการเปลี่ยนแปลง
เช่นทำการเปลี่ยนแปลง code หรือ production code เป็นต้น

ทำการ Mock มากจนเกินไป (Mock Bubble)

สิ่งสำคัญมาก ๆ สำหรับการเขียนชุดการทดสอบคือ
การแยก dependency หรือส่วนการทำงานต่าง ๆ ออกจากกัน เช่น
แยกส่วนของ Database, API, Legacy ออกจากส่วนการทำงานหลัก
หรือแยกออกไปจากส่วนที่เราสนใจ
ทำให้สามารถจำลองและส่งสิ่งที่เราต้องการใช้เข้ามา (Mock, Stub)
วิธีการนี้เรามักจะเรียกว่า Dependency Injection

แต่ถ้าส่วนที่เราสนใจมี dependency จำนวนมาก ๆ !!
ทำให้เราต้องสร้าง mock และ stub จำนวนมาก
แน่นอนว่า สามารถทดสอบได้
แต่มันคือปัญหาเรื่องการออกแบบหรือไม่ ?
ส่งผลให้ชุดการทดสอบพังได้ง่าย ?
ส่งผลให้ยากต่อการเปลี่ยนแปลงหรือไม่ ?
จำนวนของการทดสอบจะเยอะมาก ๆ ?

การทดสอบช้ามาก ๆ

เมื่อเขียนชุดการทดสอบแล้ว
ปัญหาที่มักจะตามมาคือ ใช้เวลาการทดสอบมากขึ้นเรื่อย ๆ
หมายถึงเวลาที่นั่งรอผลการทดสอบมากขึ้นเรื่อย ๆ

คำถามคือ เร็วเท่าไรดี ?
ตอบง่าย ๆ คือ เร็วกว่าเดิมและเร็วกว่าเดิม (Continuous Improvement)

ปัญหาหลัก ๆ ของการทดสอบที่ใช้เวลานาน มักประกอบไปด้วย

  • เป็น Integration test หรือไม่ ? เช่นต้องต่อกับ Database, API จริง ๆ หรือไม่ ?
  • มีการ setup ต่าง ๆ ก่อนการทดสอบเยอะและซับซ้อนมากเกินไปหรือไม่ ?
  • การทดสอบเป็นแบบ sequencial หรือไม่ ? ถ้าใช่ก็ลองเปลี่ยนไปเป็นแบบ parallel สิ
  • ระบบงานแยกเป็น module หรือ ออกแบบผิดหรือไม่ ?

ชุดการทดสอบมัน fail แบบ Random Fail

เป็นปัญหาที่น่ากลัวมาก ๆ นั่นคือ ชุดการทดสอบมัน fail แบบสุ่ม
ทั้ง ๆ ที่ไม่ได้เปลี่ยนแปลงอะไรเลย !!
input ก็หมือนเดิม แต่ทำไมผลการทำงานไม่เหมือนกัน
ทำให้ยากต่อการแก้ไขมาก ๆ
บอกได้เลยว่าโครตน่ากลัว

ปัญหานี้มักจะมาจาก
ไม่เข้าใจพฤติกรรมการทำงานของระบบเช่น
มีการทำงานแบบ asynchronous
มีการทำงานกับเวลา หรือ dependency ที่ควบคุมไม่ได้
มีการทำงานที่ใช้งาน CPU/Memory มากจนเกินไป
มีการใช้ resource pool
ออกแบบระบบผิดหรือไม่

จากนั้นก็ลงมือแก้ไขซะ

สุดท้ายสิ่งที่นักพัฒนาควรทำคือ

หัดฟังเสียงหรือผลการทำงานจากชุดการทดสอบด้วยเสมอ
จากนั้นทำการปรับปรุงให้ดีขึ้นอย่างต่อเนื่อง
ให้จำไว้เสมอว่า
ชุดการทดสอบควรมีความสำคัญเทียบเท่ากับ production code เสมอ

คำถาม
นักพัฒนาคิดว่า การทดสอบยังมีปัญหาอื่น ๆ อีกหรือไม่ ?

ขอให้สนุกกับการ coding นะครับ