เรียนรู้การทำ Unit Test
Unit Test คือการทดสอบรายฟังก์ชั่น หรือรายละเอียดส่วนเล็กๆของ Application ซึ่งกระบวนการทดสอบนี้จะทำให้เรามั่นใจได้ว่า Components หรือ Unit ต่างๆที่เรานำมาประกอบกันเป็น Application นั้นมีคุณภาพที่ดี เพราะใน Software Engineering เราจะเชื่อว่าเมื่อ Components ที่มีคุณภาพมาอยู่รวมกัน จะทำให้เกิด Application ที่มีคุณภาพตามไปด้วย เราจึงต้องดูแลคุณภาพของ Components แต่ละตัวให้อยู่ในเกณฑ์ที่เหมาะสม เหมือนกับอาหารจะอร่อยต้องเริ่มจากการคัดสรรวัตถุดิบที่ดี
ทำไมต้องมี Unit test
การมี Unit test จะช่วยเพิ่มคุณภาพของ Source code ให้เราได้ดังนี้
- Bug หรือ Defect จะน้อยลง
- เวลาเกิดการเปลี่ยนแปลงขึ้นกับระบบ เราจะเห็นผลกระทบต่อ Unit ต่างๆได้ทันที
- เราจะมั่นใจในคุณภาพของระบบได้มากขึ้น
- ทำให้ Test-cases ใน Layer ด้านบนลดลง(ดู Test Pyramid)
- เวลาที่ใช้ในการทดสอบโดยรวมจะลดลง
Google ได้ให้ตำแนะนำไว้ว่าปริมาณของ Test cases ของทั้ง 3 Layer ควรจะมีสัดส่วนเป็น
- Unit tests(70%)
- Integration tests หรือ Service-level tests(20%)
- End-to-End tests หรือ UI tests(10%)
แบบไหนที่เรียกว่า Unit test ที่ดี
- Fast: ใน 1 Project จะมีปริมาณ Unit test เป็นพัน test cases ดังนั้นเราจึงต้องควบคุมให้ Unit test ทำงานเร็วที่สุด(ต้องอยู่ในระดับ Milliseconds)
- Isolated: Unit test แต่ละตัวต้องเป็นอิสระ ไม่ขึ้นอยู่กับ Factors อื่นๆรอบข้าง(เช่น File systems หรือ Database) ดังนั้นเราจึงต้องใช้ Test Double เพื่อให้ Test case แต่ละตัวเป็นอิสระ
- Repeatable: การรัน Unit test แต่ละครั้งต้องได้รับผลลัพธ์เหมือนเดิม(ไม่เกิด Flakiness) ยิ่งเราทำให้ Unit test เป็นอิสระมากขึ้นเท่าไหร่ ก็ยิ่งทำให้เกิด Flakiness น้อยลงเท่านั้น
- Self-Checking: Unit test ต้องสามารถระบุว่า Pass หรือ Fail โดยอัตโนมัติ โดยไม่ต้องมีคนเข้าไปเกี่ยวข้อง เพราะ Unit test เป็นการทดสอบที่เหมาะกับการทำ Automated Testing มากที่สุด
- Timely: Unit test ต้องใช้เวลาในการระบุปัญหาใน Source code ให้น้อยที่สุด เพราะเป็นการทดสอบที่ใกล้ชิดกับ Source code มากที่สุด
Code Coverage
คุณภาพของ Unit test ไม่ได้ขึ้นอยู่กับจำนวน Test cases แต่จะขึ้นอยู่กับว่า Test cases นั้นครอบคลุม Source code มากแค่ไหน เราจึงใช้ Code coverage เป็นตัววัดว่า Unit test ที่เขียนนั้นมีคุณภาพมากแค่ไหน
แต่โดยปกติเราจะไม่พยายามทำให้ Code coverage เป็น 100% เพราะจะเป็นการบีบให้ Developer เน้นที่ปริมาณ(Quantity)ของ Test-case มากกว่าคุณภาพ(Quality)
ใครควรจะต้องเขียน Unit test
การเขียน Unit test ควรจะเป็นหน้าที่ของ Developer เนื่องจากการทำ Unit test จะเป็นการทดสอบแบบ White-box ซึ่งต้องเข้าถึง และเข้าใจ Source code ซึ่งคนที่น่าจะเข้าใจการทำงานของ Code มากที่สุดคือ Developer
แต่เนื่องจาก Developer ไม่ใช่ Tester ดังนั้นการออกแบบ Test-cases จึงอาจไม่ครอบคลุมทุกกรณี เราจึงต้องให้ Tester เข้าไปเป็นพี่เลี้ยงหรือเข้าไปช่วย Review test cases ต่างๆให้ จะทำให้ Unit test มีคุณภาพมากขึ้น ซึ่งในทาง Software Engineering เราเชื่อว่า
คุณภาพของ Source code ขึ้นอยู่กับคุณภาพของ Unit test
Patterns ที่ต้องใช้ในการทำ Unit test
ในการทำ Unit tests เราต้องรู้จักกับ Patterns ต่างๆเหล่านี้
Arranging Tests
เป็น Pattern สำหรับการเขียน Unit tests โดยจะแบ่ง Code ออกเป็น 3 ส่วนดังนี้
- Arrange ส่วนที่ใช้ในการ Mock หรือ เตรียม Data ก่อนจะเข้าสู่การทดสอบ(เตรียมพร้อมก่อนจะทดสอบ)
- Act เป้น Action ที่เกิดขึ้นเพื่อทดสอบ
- Assert เป็นการประเมิณว่าผลลัพธืที่ได้ออกมา Pass หรือ Fail
ทำไมต้องใช้ AAA pattern
ข้อดีของการจัด Test Code ออกเป็นส่วนๆ คือ
- แยกส่วนของการ Arrange และ Assert ออกจากกันอย่างชัดเจน
- สามารถแก้ไขหรือเพิ่ม Action เข้าไปได้ง่ายเพราะถูกแยกออกจาก Assert
Test Double
Test double คือเทคนิคที่ทำให้ Code ที่จะทำการทดสอบเป็นอิสระ(Isolated)จาก Code หรือองค์ประกอบอื่นๆ ซึ่งจะสำคัญมากๆในการทำ Unit test ซึ่งเทคนิคที่ใช้ทำ Test double มีดังนี้
- Fake คือ Object ที่ return ค่าเดิมกลับมาตลอดเวลา การ Fake เป็นส่วนสำคัญที่จะทำให้ Test cases แต่ละตัวเป็นอิสระออกจากกัน
- Stub คือ ตัวแทนของ Components ที่ต้องนำมาใช้ในการทดสอบ ซึ่ง Stub จะทำเตรียม Response สำหรับการเรียกใช้งาน Methods ต่างๆใน Components นี้
- Mock คือ ตัวแทนของ Components ที่ต้องการทดสอบเหมือนกับ Stubs แต่ Response ที่ Return กลับไปจะเปลี่ยนไปเรื่อยๆ ขึ้นอยู่กับ Scenario ของการเรียกใช้งาน ซึ่งจะมีความใก้เคียงกับการใช้งานจริงมากกว่า Stubs
- Spy คือ Code ที่ใช้ตรวจสอบ Interaction ที่เกิดขึ้นของ Object ที่ต้องการทดสอบ(ตามชื่อ Spy) เช่น จำนวนการเรียก Method ของ Object ที่ทำการทดสอบ หรือลพดับของ Methods ที่ถูกเรียกใช้งาน ดังนั้น Spy จะแตกต่างจาก Stub และ Mock ที่เตรียมผลลัพธ์ที่ต้อง Response กลับไปเฉยๆ
- Dummy คือ Code ที่ไม่ได้ใช้แต่ใส่เข้าไปเพื่อให้สามารถ Compile ได้