ทุกวันนี้ในโลกของดิจิทัล การพัฒนาแอปพลิเคชันมีมากมายหลายรูปแบบ และซับซ้อนมากขึ้นเรื่อย ๆ นักพัฒนาอย่าง Software Engineer หรือ Developer จำเป็นต้องพัฒนาทักษะกันอย่างมากเพื่อให้สามารถสร้างผลงานที่ต้องตามความต้องการของลูกค้า และทันต่อตลาด เพื่อแย่งชิงความเป็นผู้นำ หรือค้นหาโอกาสต่าง ๆ ในยุคดิจิทัลนี้
หนึ่งในวิธีที่จะยืนยันความถูกต้องของแอปพลิเคชันที่เขียนมาคือ การทดสอบ ซึ่งมีมากมายไม่ว่าเป็น เช่น UI Test, Integration Test, Manual Test, Unit Test หรืออื่น ๆ อีกมากมาย แต่ละการทดสอบก็จะมีวัตถุประสงค์ต่างกันออกไป แต่วันนี้ที่เราจะมาพูดถึงกันคือ Unit Test ซึ่งจะมีความสำคัญอย่างไร และจะมีปัญหาหรือไม่หากไม่มี Unit Test?
Unit Test คืออะไร
Unit Test เป็นวิธีการทดสอบ Software แบบหนึ่งที่ใช้ในการทดสอบส่วนที่เล็กที่สุดของ Code ซึ่งมักกระทำโดย Developer โดยจะดำเนินการเขียนชุดทดสอบตามรูปแบบการทดสอบแบบ White Box Testing เพื่อเช็กว่า Code ที่พัฒนาขึ้นมาสามารถใช้งานได้อย่างถูกต้องตามข้อตกลง หรือ Acceptance criteria หรือไม่ ก่อนที่จะส่งต่อไปยังขั้นตอนการทดสอบที่สูงกว่าเช่น Integration test ทำการทดสอบต่อไป
จุดสำคัญของ Unit test คือ เขียนทดสอบเฉพาะส่วนภายในโค้ดเท่านั้น ส่วนไหนที่เป็นภายนอกของโค้ด จะเป็นการ “Mockup ขึ้นมา” ทั้งหมด ซึ่งจะแตกต่างกันกับ Integration Test เพราะ Integration test จะต้องมีการเชื่อมต่อกับ Database หรือ Service ข้างนอกจริง
ผลลัพธ์ที่จะได้จากการทำ Unit Test นี้คือ Bug, Defect ในขั้นตอน Integration test จะน้อยลงหรือสามารถตรวจพบเจอได้ก่อนที่จะส่งมอบออกไป เพิ่มประสิทธิภาพของการ Coding ลดระยะเวลาในการทดสอบของ QA กรณี regression ได้เป็นอย่างดี รวมไปถึงยังทำให้แอปพลิเคชันของเรามีคุณภาพมากขึ้นด้วย
เริ่มต้นสร้าง Unit Test ในงานพัฒนา User Interface
สำหรับการเริ่มต้นเขียน Unit Test นั้นมี Tools ต่างมากมาย แต่ที่เราจะพูดถึงในวันนี้คือ Jest เนื่องจากเหมาะกับนักพัฒนา UI ที่เขียนด้วย React, Angular เนื่องจากเป็น JavaScript Framework สำหรับเอาไว้เขียน Test แบบ Open Source ที่พัฒนาโดย Facebook และยังมี Function ต่าง ๆ ให้เราใช้ ทำให้ง่ายต่อการเขียน Test มาก และยังมีความสามารถในการทำ Snapshot testing ซึ่งเป็นส่วนสำคัญที่จะช่วยให้ User Interface ของเราถูกต้องตามข้อกำหนดได้อีกด้วย
เรามาเริ่มสร้าง Snapshot testing โดยเริ่มจากการสร้าง Project react native ขึ้นมาใหม่แล้วสั่งรัน จะได้แอปพลิเคชั่นที่มีหน้าตาตามรูปที่แนบมาด้านล่าง
ถัดมาหลังจากที่เราสามารถรันตัวแอปพลิเคชั่นได้สำเร็จ เราก็จะมาเริ่มเขียน Snapshot testing กัน
อันดับแรกให้ไปสร้างไฟล์ App-test.js ไว้ตาม Structure ในรูป
โดยในไฟล์ของ App-test.js จะมีหน้าตาดังนี้
ถัดมาให้เรารันคำสัง Jest จะได้ผลลัพธ์ดังนี้
หลังจากรันคำสังJjest เสร็จ ให้ลองสังเกตที่ folder __test__ จะมี folder __snapshots__ ปรากฏขึ้นมาโดยมีไฟล์ App-test.js.snap อยู่ข้างใน ตามรูปที่แนบมาด้านล่าง
โดยข้างในไฟล์ App-test.js.snap นี้นี่เองที่จะเก็บผลลัพธ์จากการ render ตัว component
คราวนี่เราจะมาเริ่ม สร้าง component Section.js ขึ้นมาใหม่ ดังนี้
หลังจากนั้นให้ไปสร้างไฟล์ Section-test.js แล้วรันคำสั่ง Jest อีกครั้ง
สังเกตว่าไฟล์ Section-test.js.snap ค่อนข้างสั้นและอ่านง่ายกว่ามากเมื่อเทียบกับ App-test.js.snap ในตอนแรก
ถัดมาเราจะมาดูกันว่าถ้าเราลองเปลี่ยน สี ของ Text ใน Component จากสีดำเป็นสีอื่นอื่น ๆ ดังโค้ดด้านล่าง
{color: Colors.black}
เปลี่ยน เป็น
{color: Colors.primary}
แล้วสังเกตผลลัพธ์ที่เกิดขึ้น จะพบว่าในส่วนของหน้าตาแอปพลิเคชั่นจะแสดงผลดังนี้
Before & After
และในส่วนของผลลัพธ์จากการรัน Jest จะเห็นว่าเกิด FAIL ขึ้นที่ไฟล์ Section-test.js เนื่องจากมีการเปลี่ยนสีของ Text นั้นเอง
ซึ่งหากเรามั่นใจว่าข้อตกลงถูกต้องก็สามารถทำการอัพเดตผลลัพธ์จากการเทส โดยรันคำสั่ง jest -u แค่นี้เราก็จะสามารถอัพเดตผลการเทสได้แล้ว
จากตัวอย่างจะเห็นได้ว่า Unit Test นั้นมี คุณสมบัติ 4 ข้อ ดังนี้
- Isolate คือสามารถแยกการทดสอบออกจากกันโดยจะต้องไม่มี Dependency กับปัจจัยอื่นใด และแต่ละการทดสอบมีเป้าหมายอย่างเดียวเท่านั้น โดยการแยกส่วนการทำงานของโค้ดต่าง ๆ ออกจากกันอย่างชัดเจน
- Repeatable คือควรจะทำงานแบบอัตโนมัติและทำซ้ำได้ ควรจะสามารถใช้งานได้ไม่ว่าในอนาคตจะมีการแก้ไขโค้ดให้รองรับสำหรับ Version ใหม่ ๆ ที่เปลี่ยนแปลงไป ก็ยังสามารถนำกลับมาใช้ทดสอบเพื่อเช็กผลลัพธ์ที่ถูกต้องให้เหมือนเดิมได้อยู่
- Fast คือเขียนให้เรียกใช้งานหลาย ๆ ครั้งได้ไว ๆ จบเป็น Function ไป เพื่อไม่ให้เป็นการเสียเวลา อาจจะเลือกทำ Mock/stub object และ Inject กับ Class ที่ต้องการจะ Test เข้าไปร่วมด้วย
- Self-documenting คือการเขียน Code ที่สามารถอ่านได้ง่าย และทำตามได้ง่าย ซึ่งไม่จำเป็นต้องเขียนให้น้อยที่สุด แต่ Test ที่ดีควรที่จะต้องอธิบาย parameter และ output ของ component ได้อย่างชัดเจน และควรมีตัวอย่างของข้อมูลประกอบด้วยเสมอ
เราจะมั่นใจได้อย่างไรว่าโปรแกรมจะทำงานถูกต้องทั้งระบบ
ในความเป็นจริงในการพัฒนาทุกครั้งการมั่นใจว่าระบบสามารถทำงานได้อย่างถูกต้อง 100% คงดูเป็นเรื่องที่ใครหลายคนอยากได้แต่แทบจะไม่ได้พูดถึงกัน ถึงแม้ว่าจะเขียน UAT Test case เยอะแค่ไหนก็ตาม เราก้ยังพบว่ามี defect เกิดขึ้น Unit test อาาจะไม่สามารถการันตีได้ว่าระบบจะทำงานถูกต้อง 100% แต่อย่างน้อยก็สามารถลดโอกาสของความผิดพลาดที่จะเกิดขึ้นได้ ซึ่ง Unit Test ก็เป็นเพียงแค่จุดเริ่มต้นของการ Test สำหรับ Developer เท่านั้น เราอาจจะยังต้องมีการทำ Unit integration test, หรือการทดสอบด้าน Functional อื่น ๆ เช่น SIT, UAT เป็นต้น
นอกจากการทดสอบด้าน functional แล้ว ยังมีการทดสอบด้าน UI, Security, Performance, Deployment และการทดสอบอื่น ๆ อีกหลายส่วนเพื่อที่จะให้มั่นใจได้ว่าแอปพลิเคชันมีความพร้อมที่ปล่อยให้ผู้ใช้ ได้ใช้งานต่อไป
ปัญหาของการพัฒนาหากไม่ได้พัฒนา Unit Test เอาไว้
สุดท้ายนี้ก็อยากมาแนะนำให้ทุกคนรู้จักกับ Unit Test ยิ่งในกรณีที่เรามีการพัฒนาแอปพลิเคชันสำหรับงานชิ้นใหญ่ ๆ หรือที่ต้องมีการบำรุงรักษา หรือพัฒนาความสามารถเพิ่มเติมในระยะยาว เช่น การ Update library, os หรือการเพิ่มความสามารถอื่น ๆ เข้าไปใน feature เดิม เป็นต้น เพราะไม่เช่นนั้นแล้ว สำหรับ Developer จะต้องกลับมาตรวจสอบ Code ที่ตัวเองเขียนไปแทบทุกครั้งที่มีการแก้ไข Code เพื่อไม่ให้กระทบส่วนที่ไม่เกี่ยวข้องกับการแก้ไข ซึ่งพูดเลยว่าอาจจะเปลืองเวลา หรือใช้พลังงานไปเกินใช่เหตุ นอกจากนี้ test enginner ก็อาจจะต้องกลับมา Full regression อีกครั้ง ซึ่ง Unit Test ก็จะเป็นอีกทางเลือกหนึ่งที่สามารถช่วยให้การทำงานของ Developer และ test engineer ทำงานได้สะดวก และมีประสิทธิภาพมากขึ้น ถึงแม้ว่าช่วงแรกอาจจะต้องลงทุนเวลาในการเขียน Code แยกสำหรับทดสอบ แต่ในระยะยาวก็จะสามารถช่วยประหยัดเวลา และรักษาคุณภาพของแอปพลิเคชันไว้ได้มาก
สำหรับในตอนต่อไปเราจะนำเสนอการเขียน Unit Test ในรูปแบบของ Functional บ้าง อย่าลืมติดตามกันนะครับ
ขอบคุณข้อมูลจาก กล้า – สถาพร สายเนียม จากทีม Digital Excellence & Delivery, Bluebik Group PLC.