หากต้องการทดสอบหรือไม่ทดสอบ มุมมองทางเทคนิค

พิจารณาสิ่งที่ต้องทดสอบและสิ่งที่ตัดออกได้

บทความก่อนหน้าได้อธิบายข้อมูลเบื้องต้นเกี่ยวกับเทสเคสและสิ่งที่มีในเทสเคส บทความนี้จะเจาะลึกการสร้างกรณีทดสอบจากมุมมองทางเทคนิค โดยอธิบายรายละเอียดว่าควรรวมอะไรไว้ในการทดสอบแต่ละครั้งและควรหลีกเลี่ยงอะไร โดยพื้นฐานแล้ว คุณจะได้ทราบคำตอบสำหรับคำถามเก่าๆ อย่าง "ควรทดสอบอะไร" หรือ "ไม่ควรทดสอบอะไร"

สิ่งที่ควรทดสอบหรือไม่ทดสอบ

หลักเกณฑ์และรูปแบบทั่วไป

โปรดทราบว่ารูปแบบและจุดที่เฉพาะเจาะจงมีความสําคัญ ไม่ว่าคุณจะทำการทดสอบหน่วย การผสานรวม หรือการทดสอบจากต้นจนจบ หลักการเหล่านี้สามารถใช้และควรใช้กับการทดสอบทั้ง 2 ประเภท จึงถือเป็นจุดเริ่มต้นที่ดี

ทำให้เรียบง่าย

สิ่งสำคัญอย่างหนึ่งที่ควรคำนึงถึงเมื่อเขียนการทดสอบคือความเรียบง่าย คุณควรคำนึงถึงความสามารถของสมอง โค้ดเวอร์ชันที่ใช้งานจริงหลักใช้พื้นที่มาก จึงเหลือพื้นที่ไม่มากนักสำหรับความซับซ้อนเพิ่มเติม โดยเฉพาะอย่างยิ่งสำหรับการทดสอบ

หากมีพื้นที่ว่างน้อยลง คุณอาจผ่อนคลายมากขึ้นในการทดสอบ ด้วยเหตุนี้ การให้ความสำคัญกับความเรียบง่ายในการทดสอบจึงถือเป็นสิ่งสําคัญ อันที่จริง แนวทางปฏิบัติแนะนำสำหรับการทดสอบ JavaScript ของ Yoni Goldberg เน้นความสำคัญของกฎทองที่ว่า "การทดสอบควรเป็นเหมือนผู้ช่วย ไม่ใช่สูตรคณิตศาสตร์ที่ซับซ้อน" กล่าวคือ คุณควรเข้าใจความตั้งใจของการทดสอบได้ตั้งแต่แรกเห็น

อย่าทำให้การทดสอบซับซ้อน ผู้ทดสอบไม่ควรรู้สึกเช่นนั้น

คุณควรมุ่งเน้นความเรียบง่ายในการทดสอบทุกประเภท ไม่ว่าจะซับซ้อนเพียงใดก็ตาม อันที่จริง ยิ่งการทดสอบซับซ้อนมากเท่าใด ก็ยิ่งต้องลดความซับซ้อนลงมากเท่านั้น วิธีหนึ่งในการบรรลุเป้าหมายนี้คือการออกแบบการทดสอบแบบ Flat ซึ่งการทดสอบจะเรียบง่ายที่สุดเท่าที่จะเป็นไปได้ และทดสอบเฉพาะสิ่งที่จำเป็นเท่านั้น ซึ่งหมายความว่าการทดสอบแต่ละครั้งควรมีกรณีทดสอบเพียงรายการเดียว และกรณีทดสอบควรมุ่งเน้นที่การทดสอบฟังก์ชันการทำงานหรือฟีเจอร์ที่เฉพาะเจาะจงรายการเดียว

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

ทดสอบว่าสิ่งใดคุ้มค่า

การออกแบบการทดสอบแบบแบนยังช่วยส่งเสริมให้มุ่งเน้นและช่วยให้การทดสอบของคุณมีความหมาย โปรดทราบว่าคุณไม่ควรสร้างการทดสอบเพียงเพื่อครอบคลุมเนื้อหา แต่ควรมีจุดประสงค์เสมอ

อย่าทดสอบทุกอย่าง

อย่าทดสอบรายละเอียดการใช้งาน

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

ผลลบที่ไม่ถูกต้องเกิดขึ้นเมื่อการทดสอบไม่สําเร็จ แม้ว่าโค้ดที่ทดสอบจะถูกต้องก็ตาม ซึ่งอาจเกิดขึ้นเมื่อรายละเอียดการติดตั้งใช้งานมีการเปลี่ยนแปลงเนื่องจากการปรับโครงสร้างโค้ดแอปพลิเคชัน ในทางกลับกัน ผลบวกลวงจะเกิดขึ้นเมื่อการทดสอบผ่าน แม้ว่าโค้ดที่ทดสอบจะไม่ถูกต้องก็ตาม

วิธีแก้ปัญหาอย่างหนึ่งคือพิจารณาผู้ใช้ประเภทต่างๆ ที่คุณมี ผู้ใช้ปลายทางและนักพัฒนาซอฟต์แวร์อาจใช้แนวทางที่แตกต่างกัน และอาจโต้ตอบกับโค้ดต่างกัน เมื่อวางแผนการทดสอบ คุณต้องพิจารณาสิ่งที่ผู้ใช้จะเห็นหรือโต้ตอบด้วย และทําให้การทดสอบขึ้นอยู่กับสิ่งเหล่านั้นแทนรายละเอียดการติดตั้งใช้งาน

เช่น การเลือกตัวเลือกที่มีแนวโน้มที่จะเปลี่ยนแปลงน้อยลงอาจทําให้การทดสอบน่าเชื่อถือมากขึ้น เช่น data-attributes แทนตัวเลือก CSS ดูรายละเอียดเพิ่มเติมได้ที่ Kent C. บทความของ Dodds ในหัวข้อนี้ หรือติดตามบทความเกี่ยวกับหัวข้อนี้ที่จะเผยแพร่ในภายหลัง

การจำลอง: อย่าเสียการควบคุม

การจำลองเป็นแนวคิดที่กว้างๆ ซึ่งใช้ในการทดสอบหน่วยและบางครั้งใช้ในการทดสอบการผสานรวม ซึ่งเกี่ยวข้องกับการสร้างข้อมูลหรือคอมโพเนนต์จำลองเพื่อจําลองการพึ่งพาที่มีการควบคุมแอปพลิเคชันโดยสมบูรณ์ ซึ่งช่วยให้ทำการทดสอบแบบแยกได้

การใช้การจําลองในการทดสอบจะช่วยปรับปรุงการคาดการณ์ การแยกข้อกังวล และประสิทธิภาพ และหากต้องทำการทดสอบที่ต้องอาศัยการมีส่วนร่วมของมนุษย์ (เช่น การยืนยันหนังสือเดินทาง) คุณจะต้องปกปิดข้อมูลโดยใช้การจำลอง ด้วยเหตุนี้ โมคจึงถือเป็นเครื่องมือที่มีประโยชน์ที่ควรพิจารณา

ในขณะเดียวกัน การจำลองอาจส่งผลต่อความแม่นยำของการทดสอบ เนื่องจากเป็นการจำลอง ไม่ใช่ประสบการณ์การใช้งานจริงของผู้ใช้ คุณจึงต้องใช้โม็กและสตับอย่างระมัดระวัง

คุณควรจำลองในการทดสอบจากต้นทางถึงปลายทางหรือไม่

โดยทั่วไปแล้ว ไม่ได้ แต่การจำลองอาจช่วยแก้ปัญหาได้บ้างในบางครั้ง ดังนั้นเราจึงไม่ควรปิดโอกาสนี้ไปเลย

ลองจินตนาการถึงสถานการณ์นี้ คุณกำลังเขียนการทดสอบสำหรับฟีเจอร์ที่เกี่ยวข้องกับบริการของผู้ให้บริการการชำระเงินบุคคลที่สาม คุณอยู่ในสภาพแวดล้อมเสมือนจริงที่บริษัทได้จัดเตรียมไว้ ซึ่งหมายความว่าจะไม่มีธุรกรรมจริงเกิดขึ้น ขออภัย Sandbox ทำงานผิดปกติ จึงทําให้การทดสอบไม่สําเร็จ ผู้ให้บริการชำระเงินต้องเป็นผู้ดำเนินการแก้ไข สิ่งที่คุณทำได้คือรอให้ผู้ให้บริการแก้ไขปัญหา

ในกรณีนี้ การลดการพึ่งพาบริการที่คุณควบคุมไม่ได้อาจเป็นประโยชน์มากกว่า เรายังคงแนะนำให้ใช้การจำลองอย่างระมัดระวังในการทดสอบการผสานรวมหรือการทดสอบจากต้นทางถึงปลายทาง เนื่องจากจะลดระดับความเชื่อมั่นของการทดสอบ

รายละเอียดการทดสอบ: สิ่งที่ควรและไม่ควรทำ

สรุปแล้ว การทดสอบประกอบด้วยอะไรบ้าง และการทดสอบแต่ละประเภทมีความแตกต่างกันไหม มาดูรายละเอียดของบางแง่มุมที่ปรับให้เหมาะกับการทดสอบประเภทหลักกัน

องค์ประกอบของ Unit Test ที่ดีมีอะไรบ้าง

การทดสอบ 1 หน่วยที่เหมาะและมีประสิทธิภาพควรมีลักษณะดังนี้

  • มุ่งเน้นที่บางแง่มุม
  • ทำงานได้อย่างอิสระ
  • ครอบคลุมสถานการณ์ขนาดเล็ก
  • ใช้ชื่อที่สื่อความหมาย
  • ทำตามรูปแบบ AAA หากมี
  • รับประกันการทดสอบที่ครอบคลุม
สิ่งที่ควรทำ ✅ สิ่งที่ไม่ควรทำ ❌
ทดสอบให้น้อยที่สุด ทดสอบทีละรายการต่อกรอบการทดสอบ เขียนการทดสอบในหน่วยขนาดใหญ่
แยกการทดสอบไว้เสมอและจำลองสิ่งที่คุณต้องการซึ่งอยู่นอกยูนิต ใส่คอมโพเนนต์หรือบริการอื่นๆ
ทดสอบแยกกัน ใช้การทดสอบก่อนหน้านี้หรือแชร์ข้อมูลการทดสอบ
ครอบคลุมสถานการณ์และเส้นทางต่างๆ จำกัดการทดสอบให้อยู่ในเส้นทางที่ถูกต้องหรือทดสอบเชิงลบเป็นส่วนใหญ่
ใช้ชื่อการทดสอบที่สื่อความหมายเพื่อให้คุณเห็นสิ่งที่จะทดสอบได้ทันที ทดสอบตามชื่อฟังก์ชันเท่านั้น สื่อความหมายไม่เพียงพอ testBuildFoo() หรือ testGetId()
มุ่งเน้นที่การครอบคลุมโค้ดที่ดีหรือกรณีทดสอบที่หลากหลายมากขึ้น โดยเฉพาะในระยะนี้ ทดสอบจากทุกคลาสไปจนถึงระดับฐานข้อมูล (I/O)

การทดสอบการผสานรวมที่ดีควรมีลักษณะอย่างไร

การทดสอบการผสานรวมที่เหมาะสมจะมีเกณฑ์บางอย่างร่วมกับการทดสอบ 1 หน่วยด้วย อย่างไรก็ตาม ยังมีอีก 2 ประเด็นที่คุณควรพิจารณา การทดสอบการผสานรวมที่ดีควรมีลักษณะดังนี้

  • จำลองการโต้ตอบระหว่างคอมโพเนนต์
  • ครอบคลุมสถานการณ์ในชีวิตจริง และใช้การจําลองหรือสแต็บ
  • พิจารณาประสิทธิภาพ
สิ่งที่ควรทำ ✅ สิ่งที่ไม่ควรทำ ❌
ทดสอบจุดผสานรวม: ยืนยันว่าแต่ละหน่วยทำงานร่วมกันได้อย่างราบรื่นเมื่อผสานรวมกัน ทดสอบแต่ละหน่วยแยกกัน นั่นคือวัตถุประสงค์ของ Unit Test
ทดสอบสถานการณ์ในชีวิตจริง: ใช้ข้อมูลทดสอบที่มาจากข้อมูลในชีวิตจริง ใช้ข้อมูลทดสอบที่สร้างขึ้นโดยอัตโนมัติซ้ำๆ หรือข้อมูลอื่นๆ ที่ไม่ได้แสดงถึง Use Case ในชีวิตจริง
ใช้การจําลองและสตับสําหรับทรัพยากรภายนอกเพื่อควบคุมการทดสอบที่สมบูรณ์ สร้างการพึ่งพาบริการของบุคคลที่สาม เช่น คำขอเครือข่ายไปยังบริการภายนอก
ใช้กิจวัตรการล้างข้อมูลก่อนและหลังการทดสอบแต่ละครั้ง ลืมใช้มาตรการล้างข้อมูลภายในการทดสอบ ไม่เช่นนั้นอาจทําให้การทดสอบไม่สําเร็จหรือเกิดผลบวกลวงได้ เนื่องจากไม่มีการแยกการทดสอบที่เหมาะสม

การทดสอบจากต้นทางถึงปลายทางที่ดีควรมีลักษณะอย่างไร

การทดสอบจากต้นจนจบที่ครอบคลุมควรมีลักษณะดังนี้

  • จำลองการโต้ตอบของผู้ใช้
  • ครอบคลุมสถานการณ์ที่สำคัญ
  • ครอบคลุมหลายเลเยอร์
  • จัดการการดำเนินการแบบไม่พร้อมกัน
  • ยืนยันผลลัพธ์
  • คำนึงถึงประสิทธิภาพ
สิ่งที่ควรทำ ✅ สิ่งที่ไม่ควรทำ ❌
ใช้ทางลัดที่ขับเคลื่อนโดย API ดูข้อมูลเพิ่มเติม ใช้การโต้ตอบ UI สําหรับทุกขั้นตอน รวมถึงฮุก beforeEach
ใช้กิจวัตรการล้างข้อมูลก่อนการทดสอบแต่ละครั้ง ให้ความสำคัญกับการแยกการทดสอบมากกว่าการทดสอบหน่วยและการทดสอบการผสานรวม เนื่องจากมีความเสี่ยงที่จะเกิดผลข้างเคียงมากกว่า ลืมล้างข้อมูลหลังจากการทดสอบแต่ละครั้ง หากคุณไม่ล้างสถานะ ข้อมูล หรือผลข้างเคียงที่เหลืออยู่ สถานะ ข้อมูล หรือผลข้างเคียงเหล่านั้นจะส่งผลต่อการทดสอบอื่นๆ ที่ดำเนินการในภายหลัง
ถือว่าการทดสอบจากต้นทางถึงปลายทางเป็นการทดสอบระบบ ซึ่งหมายความว่าคุณต้องทดสอบทั้งสแต็กแอปพลิเคชัน ทดสอบแต่ละหน่วยแยกกัน นั่นคือวัตถุประสงค์ของ Unit Test
ใช้การจำลองให้น้อยที่สุดหรือไม่ใช้เลยในการทดสอบ โปรดพิจารณาอย่างรอบคอบหากต้องการจำลองการพึ่งพาภายนอก ใช้การจำลองเป็นหลัก
พิจารณาประสิทธิภาพและปริมาณงาน เช่น ไม่ทดสอบสถานการณ์ขนาดใหญ่มากเกินไปในการทดสอบเดียวกัน ครอบคลุมเวิร์กโฟลว์ขนาดใหญ่โดยไม่ต้องใช้แป้นพิมพ์ลัด