อ่าน 10 นาที
การทดสอบหน่วย
การทดสอบหน่วยหรือที่เรียกว่า การทดสอบ ส่วนประกอบหรือโมดูลเป็นรูปแบบหนึ่งของการทดสอบซอฟต์แวร์โดย การทดสอบ ซอร์สโค้ด ที่แยกออกมา เพื่อตรวจสอบพฤติกรรมที่คาดหวัง
การทดสอบหน่วย
| ส่วนหนึ่งของชุดบทความเกี่ยวกับ |
| การพัฒนาซอฟต์แวร์ |
|---|
การทดสอบหน่วยหรือที่เรียกว่า การทดสอบ ส่วนประกอบหรือโมดูลเป็นรูปแบบหนึ่งของการทดสอบซอฟต์แวร์โดย การทดสอบ ซอร์สโค้ด ที่แยกออกมา เพื่อตรวจสอบพฤติกรรมที่คาดหวัง[ 1 ]
การทดสอบหน่วยหมายถึงการทดสอบที่ดำเนินการในระดับหน่วยเพื่อเปรียบเทียบกับการทดสอบใน ระดับ การรวมระบบหรือระดับระบบ[ 2 ]
ประวัติศาสตร์
การทดสอบหน่วย (Unit testing) ซึ่งเป็นหลักการสำหรับการทดสอบส่วนย่อยของระบบซอฟต์แวร์ขนาดใหญ่แยกกัน มีมาตั้งแต่ยุคแรกเริ่มของวิศวกรรมซอฟต์แวร์ ในเดือนมิถุนายน พ.ศ. 2499 ในงานสัมมนาเรื่องวิธีการเขียนโปรแกรมขั้นสูงสำหรับคอมพิวเตอร์ดิจิทัลของกองทัพเรือสหรัฐฯ HD Benington ได้นำเสนอ โครงการ SAGEซึ่งมีแนวทางตามข้อกำหนด โดยขั้นตอนการเขียนโค้ดจะตามด้วย "การทดสอบพารามิเตอร์" เพื่อตรวจสอบความถูกต้องของโปรแกรมย่อยตามข้อกำหนด จากนั้นจึงตามด้วย "การทดสอบการประกอบ" สำหรับชิ้นส่วนที่ประกอบเข้าด้วยกัน[ 3 ] [ 4 ]
ในปี พ.ศ. 2507 ได้มีการอธิบายแนวทางที่คล้ายกันสำหรับซอฟต์แวร์ของโครงการเมอร์คิวรีโดยที่แต่ละหน่วยที่พัฒนาโดยโปรแกรมเมอร์ที่แตกต่างกันจะต้องผ่าน "การทดสอบหน่วย" ก่อนที่จะรวมเข้าด้วยกัน[ 5 ] ในปี พ.ศ. 2512 วิธีการทดสอบดูเหมือนจะมีโครงสร้างมากขึ้น โดยการทดสอบหน่วย การทดสอบส่วนประกอบ และการทดสอบการรวมระบบจะช่วยตรวจสอบความถูกต้องของชิ้นส่วนแต่ละชิ้นที่เขียนแยกกันและการประกอบชิ้นส่วนเหล่านั้นเข้าด้วยกันเป็นบล็อกขนาดใหญ่[ 6 ] มาตรฐานสาธารณะบางมาตรฐานที่นำมาใช้ในช่วงปลายทศวรรษ พ.ศ. 2503 เช่น MIL-STD-483 [ 7 ]และ MIL-STD-490 ได้ส่งเสริมให้การทดสอบหน่วยเป็นที่ยอมรับอย่างกว้างขวางในโครงการขนาดใหญ่
ในสมัยนั้น การทดสอบหน่วยเป็นแบบโต้ตอบ[ 4 ]หรือแบบอัตโนมัติ[ 8 ] โดยใช้การทดสอบแบบเขียนโค้ดหรือเครื่องมือทดสอบแบบจับภาพและเล่นซ้ำ ในปี 1989 Kent Beckได้อธิบายกรอบการทำงานการทดสอบสำหรับSmalltalk (ต่อมาเรียกว่าSUnit ) ใน " Simple Smalltalk Testing: With Patterns " ในปี 1997 Kent BeckและErich Gammaได้พัฒนาและเผยแพร่JUnitซึ่งเป็นกรอบการทำงานการทดสอบหน่วยที่ได้รับความนิยมในหมู่นักพัฒนาJava [ 9 ] Googleได้นำการทดสอบอัตโนมัติมาใช้ในช่วงประมาณปี 2005–2006 [ 10 ]
หน่วย
หน่วยถูกกำหนดให้เป็นพฤติกรรมเดียวที่แสดงโดยระบบที่กำลังทดสอบ (SUT) ซึ่งโดยปกติจะสอดคล้องกับข้อกำหนด ในขณะที่หน่วยอาจสอดคล้องกับฟังก์ชันหรือโมดูลเดียว (ในการเขียนโปรแกรมเชิงกระบวนการ ) หรือเมธอดหรือคลาสเดียว (ในการเขียนโปรแกรมเชิงวัตถุ ) ฟังก์ชัน/เมธอดและโมดูล/คลาสไม่จำเป็นต้องสอดคล้องกับหน่วย จากมุมมองของข้อกำหนดของระบบ มีเพียงขอบเขตของระบบเท่านั้นที่เกี่ยวข้อง ดังนั้นมีเพียงจุดเริ่มต้นของพฤติกรรมระบบที่มองเห็นได้จากภายนอกเท่านั้นที่กำหนดหน่วย[ 11 ]
การประหารชีวิต
การทดสอบหน่วยสามารถทำได้ด้วยตนเองหรือโดย การดำเนินการ ทดสอบอัตโนมัติการทดสอบอัตโนมัติมีข้อดีหลายประการ เช่น การทดสอบบ่อยครั้ง การทดสอบโดยไม่ต้องเสียค่าใช้จ่ายด้านบุคลากร และการทดสอบที่สม่ำเสมอและทำซ้ำได้
โดยทั่วไปแล้ว โปรแกรมเมอร์ที่เขียนและแก้ไขโค้ดที่กำลังทดสอบมักจะทำการทดสอบด้วยตนเอง การทดสอบหน่วย (Unit testing) อาจมองได้ว่าเป็นส่วนหนึ่งของกระบวนการเขียนโค้ด
เกณฑ์การทดสอบ
ในระหว่างการพัฒนา โปรแกรมเมอร์อาจเขียนเกณฑ์หรือผลลัพธ์ที่ทราบว่าดีลงในชุดทดสอบเพื่อตรวจสอบความถูกต้องของหน่วยนั้นๆ
ในระหว่างการดำเนินการทดสอบ เฟรมเวิร์กจะบันทึกการทดสอบที่ล้มเหลวตามเกณฑ์ใดๆ และรายงานผลในรูปแบบสรุป
สำหรับกรณีนี้ วิธีที่นิยมใช้มากที่สุดคือ การทดสอบ - ฟังก์ชัน - ค่าที่คาดหวัง
กรณีทดสอบ
ในวิศวกรรมซอฟต์แวร์กรณีทดสอบคือข้อกำหนดของอินพุต เงื่อนไขการดำเนินการ ขั้นตอนการทดสอบ และผลลัพธ์ที่คาดหวัง ซึ่งกำหนดการทดสอบเดียวที่จะดำเนินการเพื่อให้บรรลุ วัตถุประสงค์ การทดสอบซอฟต์แวร์ เฉพาะ เช่น การทดสอบเส้นทางโปรแกรมเฉพาะ หรือการตรวจสอบการปฏิบัติตามข้อกำหนดเฉพาะ[ 12 ]กรณีทดสอบเป็นพื้นฐานของการทดสอบที่เป็นระบบมากกว่าแบบสุ่ม สามารถสร้าง ชุดกรณีทดสอบเพื่อให้ได้ความครอบคลุมที่ต้องการของซอฟต์แวร์ที่กำลังทดสอบ กรณีทดสอบที่กำหนดไว้อย่างเป็นทางการช่วยให้สามารถเรียกใช้การทดสอบเดียวกันซ้ำ ๆ กับซอฟต์แวร์เวอร์ชันต่อ ๆ กันได้ ทำให้การทดสอบการถดถอยมีประสิทธิภาพและสม่ำเสมอ[ 13 ]
ทดสอบสองเท่า
Test Doubleคือซอฟต์แวร์ที่ใช้ในระบบอัตโนมัติการทดสอบซอฟต์แวร์ ซึ่งทำหน้าที่ตอบสนอง ความต้องการด้าน การพึ่งพา (dependency)เพื่อให้การทดสอบไม่จำเป็นต้องพึ่งพาโค้ดที่ใช้งานจริง Test Double จะให้ฟังก์ชันการทำงานผ่านทางอินเทอร์เฟซที่ซอฟต์แวร์ที่กำลังทดสอบไม่สามารถแยกแยะความแตกต่างจากโค้ดที่ใช้งานจริงได้
การทดสอบแบบกำหนดพารามิเตอร์
การทดสอบแบบมีพารามิเตอร์คือการทดสอบที่ยอมรับชุดค่าต่างๆ ซึ่งสามารถใช้เพื่อทำให้การทดสอบทำงานได้กับค่าอินพุตที่แตกต่างกันหลายค่า เฟรมเวิร์กการทดสอบที่รองรับการทดสอบแบบมีพารามิเตอร์ จะมีวิธีในการเข้ารหัสชุดพารามิเตอร์และเรียกใช้การทดสอบกับแต่ละชุดค่าพารามิเตอร์
การใช้การทดสอบแบบกำหนดพารามิเตอร์สามารถลดการเขียนโค้ดทดสอบซ้ำซ้อนได้
การทดสอบแบบพารามิเตอร์ได้รับการสนับสนุนโดยTestNG , JUnit , [ 14 ] XUnitและNUnitรวมถึงเฟรมเวิร์กการทดสอบ JavaScript ต่างๆ
พารามิเตอร์สำหรับการทดสอบหน่วยอาจถูกเขียนโค้ดด้วยตนเองหรือในบางกรณีอาจถูกสร้างขึ้นโดยอัตโนมัติโดยเฟรมเวิร์กการทดสอบ ในช่วงไม่กี่ปีที่ผ่านมา มีการเพิ่มการสนับสนุนสำหรับการเขียนการทดสอบ (หน่วย) ที่มีประสิทธิภาพมากขึ้น โดยใช้ประโยชน์จากแนวคิดของทฤษฎี กรณีทดสอบที่ดำเนินการตามขั้นตอนเดียวกัน แต่ใช้ข้อมูลทดสอบที่สร้างขึ้นในขณะรันไทม์ ซึ่งแตกต่างจากการทดสอบแบบพารามิเตอร์ทั่วไปที่ใช้ขั้นตอนการดำเนินการเดียวกันกับชุดอินพุตที่กำหนดไว้ล่วงหน้า[ 15 ]
การมองเห็นโค้ด
โค้ดทดสอบจำเป็นต้องเข้าถึงโค้ดที่กำลังทดสอบ แต่การทดสอบไม่ควรบั่นทอนเป้าหมายการออกแบบปกติ เช่นการซ่อนข้อมูลการห่อหุ้ม และการแยกส่วนความรับผิดชอบเพื่อให้สามารถเข้าถึงโค้ดที่ไม่เปิดเผยใน API ภายนอกได้ การทดสอบหน่วยสามารถอยู่ในโปรเจกต์หรือโมดูล เดียวกัน กับโค้ดที่กำลังทดสอบได้
ในการออกแบบเชิงวัตถุวิธีนี้อาจยังไม่สามารถเข้าถึงข้อมูลและเมธอดส่วนตัวได้ ดังนั้น อาจจำเป็นต้องทำงานเพิ่มเติมสำหรับการทดสอบหน่วย ในJavaและภาษาอื่นๆ นักพัฒนาสามารถใช้การสะท้อนเพื่อเข้าถึงฟิลด์และเมธอดส่วนตัวได้[ 16 ]หรืออีกทางหนึ่ง สามารถใช้ คลาสภายในเพื่อเก็บการทดสอบหน่วยเพื่อให้สามารถมองเห็นสมาชิกและแอตทริบิวต์ของคลาสที่ครอบคลุมได้ ใน . NET Frameworkและภาษาการเขียนโปรแกรมอื่นๆ บางภาษา สามารถใช้ คลาสบางส่วนเพื่อเปิดเผยเมธอดและข้อมูลส่วนตัวเพื่อให้การทดสอบเข้าถึงได้
สิ่งสำคัญคือโค้ดที่ใช้เพื่อรองรับการทดสอบเพียงอย่างเดียวไม่ควรอยู่ในโค้ดที่ใช้งานจริง ใน ภาษา Cและภาษาอื่นๆคำสั่งคอมไพเลอร์เช่น#if DEBUG ... #endif`@test_class` สามารถวางไว้รอบๆ คลาสเพิ่มเติมเหล่านี้ และโค้ดอื่นๆ ที่เกี่ยวข้องกับการทดสอบทั้งหมด เพื่อป้องกันไม่ให้ถูกคอมไพล์รวมอยู่ในโค้ดที่เผยแพร่ ซึ่งหมายความว่าโค้ดที่เผยแพร่จะไม่เหมือนกับโค้ดที่ผ่านการทดสอบหน่วย (unit test) ทุกประการ การรันการทดสอบแบบบูรณาการ (integration test) ที่ครอบคลุมมากขึ้น แต่มีจำนวนน้อยลง ในเวอร์ชันที่เผยแพร่ขั้นสุดท้าย จะช่วยให้มั่นใจได้ว่า (ในบรรดาสิ่งอื่นๆ) ไม่มีโค้ดที่ใช้งานจริงที่พึ่งพาองค์ประกอบบางส่วนของชุดทดสอบ (test harness ) อย่างแนบเนียน
มีการถกเถียงกันในหมู่นักพัฒนาซอฟต์แวร์ว่าควรทดสอบเมธอดและข้อมูลส่วนตัวหรือไม่ บางคนแย้งว่าสมาชิกส่วนตัวเป็นเพียงรายละเอียดการใช้งานที่อาจเปลี่ยนแปลงได้ และควรอนุญาตให้เปลี่ยนแปลงได้โดยไม่ต้องทำลายการทดสอบจำนวนมาก ดังนั้นการทดสอบคลาสใดๆ ผ่านอินเทอร์เฟซสาธารณะหรือผ่านอินเทอร์เฟซของคลาสย่อย ซึ่งบางภาษาเรียกว่าอินเทอร์เฟซ "protected" ก็เพียงพอแล้ว[ 17 ]คนอื่นๆ กล่าวว่าแง่มุมที่สำคัญของฟังก์ชันการทำงานอาจถูกนำไปใช้ในเมธอดส่วนตัว และการทดสอบโดยตรงจะให้ข้อดีของการทดสอบหน่วยที่เล็กกว่าและตรงกว่า[ 18 ] [ 19 ]
การพัฒนาแบบทดสอบนำ
ในการพัฒนาแบบทดสอบนำ (Test-Driven Development หรือ TDD) นั้น จะเขียน Unit Test ก่อนที่จะเขียนโค้ดส่วนที่เกี่ยวข้อง โดยเริ่มจาก Test ที่ล้มเหลว จากนั้นจึงเพิ่ม โค้ดส่วนที่ใช้งานจริง เข้าไปเพียงพอที่จะทำให้ Test ผ่าน แล้วจึงปรับปรุงโค้ดตามความเหมาะสม และทำซ้ำโดยเพิ่ม Test ที่ล้มเหลวอีกครั้ง
ค่า
การทดสอบหน่วยมีจุดประสงค์เพื่อให้แน่ใจว่าหน่วยต่างๆ ตรงตามการออกแบบและทำงานตามที่ตั้งใจไว้[ 20 ]
โดยการเขียนการทดสอบก่อนสำหรับหน่วยที่ทดสอบได้ขนาดเล็กที่สุด จากนั้นจึงทดสอบพฤติกรรมแบบผสมระหว่างหน่วยเหล่านั้น จะสามารถสร้างการทดสอบที่ครอบคลุมสำหรับแอปพลิเคชันที่ซับซ้อนได้[ 20 ]
เป้าหมายหนึ่งของการทดสอบหน่วยคือการแยกแต่ละส่วนของโปรแกรมและแสดงให้เห็นว่าแต่ละส่วนนั้นถูกต้อง[ 1 ]การทดสอบหน่วยให้สัญญาที่ เป็นลายลักษณ์อักษรที่เข้มงวด ซึ่งโค้ดชิ้นนั้นต้องปฏิบัติตาม
การตรวจพบปัญหาตั้งแต่เนิ่นๆ ในช่วงเริ่มต้นของวงจรการพัฒนา
การทดสอบหน่วยช่วยค้นหาปัญหาตั้งแต่ช่วงต้นของวงจรการพัฒนาซึ่งรวมถึงทั้งบั๊กในการใช้งานของโปรแกรมเมอร์และข้อบกพร่องหรือส่วนที่ขาดหายไปของข้อกำหนดสำหรับหน่วย กระบวนการเขียนชุดการทดสอบอย่างละเอียดจะบังคับให้ผู้เขียนคิดผ่านอินพุต เอาต์พุต และเงื่อนไขข้อผิดพลาด และด้วยเหตุนี้จึงสามารถกำหนดพฤติกรรมที่ต้องการของหน่วยได้อย่างชัดเจนยิ่งขึ้น[ 21 ]
ต้นทุนที่ลดลง
ต้นทุนในการค้นหาข้อผิดพลาดก่อนเริ่มเขียนโค้ดหรือเมื่อเขียนโค้ดครั้งแรกนั้นต่ำกว่าต้นทุนในการตรวจจับ ระบุ และแก้ไขข้อผิดพลาดในภายหลังอย่างมาก ข้อผิดพลาดในโค้ดที่เผยแพร่แล้วอาจทำให้เกิดปัญหาที่มีค่าใช้จ่ายสูงสำหรับผู้ใช้ซอฟต์แวร์[ 22 ] [ 23 ] [ 24 ]โค้ดอาจไม่สามารถทดสอบหน่วยได้หรือทำได้ยากหากเขียนไม่ดี ดังนั้นการทดสอบหน่วยจึงสามารถบังคับให้นักพัฒนาจัดโครงสร้างฟังก์ชันและวัตถุในรูปแบบที่ดีขึ้นได้
การเผยแพร่ที่บ่อยขึ้น
การทดสอบหน่วยช่วยให้สามารถปล่อยเวอร์ชันใหม่ได้บ่อยขึ้นในการพัฒนาซอฟต์แวร์ โดยการทดสอบส่วนประกอบแต่ละส่วนแยกกัน นักพัฒนาสามารถระบุและแก้ไขปัญหาได้อย่างรวดเร็ว ส่งผลให้รอบการพัฒนาและการปล่อยเวอร์ชันใหม่เร็วขึ้น[ 25 ]
ช่วยให้สามารถปรับปรุงโครงสร้างโค้ดได้
การทดสอบหน่วยช่วยให้โปรแกรมเมอร์สามารถปรับปรุงโค้ดหรืออัปเกรดไลบรารีของระบบในภายหลังได้ และตรวจสอบให้แน่ใจว่าโมดูลยังคงทำงานได้อย่างถูกต้อง (เช่น ในการทดสอบการถดถอย ) ขั้นตอนคือการเขียนกรณีทดสอบสำหรับฟังก์ชันและเมธอด ทั้งหมด เพื่อให้สามารถระบุข้อผิดพลาดได้อย่างรวดเร็วเมื่อใดก็ตามที่มีการเปลี่ยนแปลงเกิดขึ้น
ตรวจจับการเปลี่ยนแปลงที่อาจทำให้สัญญาการออกแบบเป็นโมฆะ
การทดสอบหน่วย (Unit tests) ตรวจจับการเปลี่ยนแปลงที่อาจทำให้ข้อตกลงด้านการออกแบบเสียหาย
ลดความไม่แน่นอน
การทดสอบหน่วยย่อยอาจช่วยลดความไม่แน่นอนในตัวหน่วยย่อยเอง และสามารถใช้ใน แนวทางการทดสอบแบบ จากล่างขึ้นบนได้โดยการทดสอบส่วนต่างๆ ของโปรแกรมก่อน แล้วจึงทดสอบผลรวมของส่วนต่างๆ เหล่านั้นการทดสอบการบูรณาการจึงง่ายขึ้นมาก
เอกสารบันทึกพฤติกรรมของระบบ
โปรแกรมเมอร์บางคนโต้แย้งว่าการทดสอบหน่วยเป็นรูปแบบหนึ่งของเอกสารประกอบโค้ด นักพัฒนาที่ต้องการเรียนรู้ว่าหน่วยนั้นมีฟังก์ชันการทำงานอะไรบ้าง และวิธีการใช้งาน สามารถตรวจสอบการทดสอบหน่วยเพื่อทำความเข้าใจได้[ 26 ]
กรณีทดสอบสามารถแสดงถึงลักษณะที่สำคัญต่อความสำเร็จของหน่วยทดสอบได้ ลักษณะเหล่านี้สามารถบ่งชี้ถึงการใช้งานหน่วยทดสอบที่เหมาะสม/ไม่เหมาะสม รวมถึงพฤติกรรมเชิงลบที่หน่วยทดสอบจะต้องตรวจจับได้ กรณีทดสอบจะบันทึกลักษณะที่สำคัญเหล่านี้ไว้ แม้ว่าสภาพแวดล้อมการพัฒนาซอฟต์แวร์หลายแห่งจะไม่พึ่งพาโค้ดเพียงอย่างเดียวในการบันทึกผลิตภัณฑ์ที่กำลังพัฒนาอยู่ก็ตาม
ในบางกระบวนการ การกระทำของการเขียนการทดสอบและโค้ดที่อยู่ภายใต้การทดสอบ รวมทั้งการปรับโครงสร้างที่เกี่ยวข้อง อาจเข้ามาแทนที่การออกแบบอย่างเป็นทางการ การทดสอบหน่วยแต่ละครั้งสามารถมองได้ว่าเป็นองค์ประกอบการออกแบบที่ระบุคลาส เมธอด และพฤติกรรมที่สังเกตได้[ 27 ]
ข้อจำกัดและข้อเสีย
การทดสอบจะไม่สามารถตรวจจับข้อผิดพลาดทุกอย่างในโปรแกรมได้ เพราะไม่สามารถประเมินเส้นทางการทำงานทุกเส้นทางได้ ยกเว้นในโปรแกรมที่ง่ายที่สุดปัญหา นี้ เป็นส่วนขยายของปัญหาการหยุดทำงานซึ่งเป็น ปัญหา ที่ไม่สามารถตัดสินได้เช่นเดียวกับการทดสอบหน่วย นอกจากนี้ การทดสอบหน่วยตามนิยามแล้วจะทดสอบเฉพาะฟังก์ชันการทำงานของหน่วยนั้นๆ เท่านั้น ดังนั้นจึงไม่สามารถตรวจจับข้อผิดพลาดในการรวมระบบหรือข้อผิดพลาดระดับระบบที่กว้างกว่า (เช่น ฟังก์ชันที่ทำงานข้ามหลายหน่วย หรือพื้นที่ทดสอบที่ไม่เกี่ยวข้องกับฟังก์ชันการทำงาน เช่นประสิทธิภาพ ) การทดสอบหน่วยควรทำควบคู่ไปกับ กิจกรรม การทดสอบซอฟต์แวร์ อื่นๆ เนื่องจากสามารถแสดงให้เห็นได้เพียงการมีอยู่หรือไม่มีอยู่ของข้อผิดพลาดเฉพาะเท่านั้น ไม่สามารถพิสูจน์ได้ว่าไม่มีข้อผิดพลาดโดยสิ้นเชิง เพื่อรับประกันพฤติกรรมที่ถูกต้องสำหรับทุกเส้นทางการทำงานและทุกอินพุตที่เป็นไปได้ และเพื่อให้แน่ใจว่าไม่มีข้อผิดพลาด จำเป็นต้องใช้เทคนิคอื่นๆ นั่นคือ การประยุกต์ใช้วิธีการเชิงรูปธรรมเพื่อพิสูจน์ว่าส่วนประกอบซอฟต์แวร์ไม่มีพฤติกรรมที่ไม่คาดคิด
ลำดับชั้นที่ซับซ้อนของการทดสอบหน่วยไม่ได้หมายความว่าเป็นการทดสอบการบูรณาการเสมอไป การบูรณาการกับหน่วยภายนอกควรถูกรวมอยู่ในการทดสอบการบูรณาการ ไม่ใช่การทดสอบหน่วย โดยทั่วไปแล้ว การทดสอบการบูรณาการยังคงพึ่งพาการทดสอบด้วยตนเอง ของมนุษย์เป็นอย่างมาก การทดสอบระดับสูงหรือการทดสอบในขอบเขตทั่วโลกอาจยากที่จะทำให้เป็นอัตโนมัติ ดังนั้นการทดสอบด้วยตนเองจึงมักดูเร็วกว่าและประหยัดกว่า
การทดสอบซอฟต์แวร์เป็นปัญหาเชิงการจัดเรียง ตัวอย่างเช่น คำสั่งตัดสินใจแบบบูลีนทุกคำสั่งต้องมีการทดสอบอย่างน้อยสองครั้ง ครั้งหนึ่งมีผลลัพธ์เป็น "จริง" และอีกครั้งหนึ่งมีผลลัพธ์เป็น "เท็จ" ดังนั้น สำหรับโค้ดทุกบรรทัดที่เขียน โปรแกรมเมอร์มักจะต้องใช้โค้ดทดสอบ 3 ถึง 5 บรรทัด ซึ่งเห็นได้ชัดว่าต้องใช้เวลา และการลงทุนนี้อาจไม่คุ้มค่ากับความพยายาม มีปัญหาบางอย่างที่ไม่สามารถทดสอบได้ง่ายๆ เลย เช่น ปัญหาที่ไม่สามารถกำหนดได้หรือปัญหาที่เกี่ยวข้องกับเธรด หลายตัว นอกจากนี้ โค้ดสำหรับการทดสอบหน่วยก็มีโอกาสที่จะมีข้อบกพร่องได้พอๆ กับโค้ดที่กำลังทดสอบFred BrooksในThe Mythical Man-Monthกล่าวว่า "อย่าออกทะเลไปกับนาฬิกาจับเวลาสองเรือน ให้เอาไปหนึ่งหรือสามเรือน" [ 28 ] (ถ้านาฬิกา จับเวลาสองเรือน ขัดแย้งกัน ก็ไม่สามารถรู้ได้ว่าเรือนไหนถูกต้อง)
ความยากลำบากในการจัดตั้งการทดสอบที่สมจริงและมีประโยชน์
ความท้าทายอีกประการหนึ่งที่เกี่ยวข้องกับการเขียนการทดสอบหน่วยคือความยากลำบากในการตั้งค่าการทดสอบที่สมจริงและมีประโยชน์ จำเป็นต้องสร้างเงื่อนไขเริ่มต้นที่เกี่ยวข้องเพื่อให้ส่วนของแอปพลิเคชันที่กำลังทดสอบทำงานเหมือนเป็นส่วนหนึ่งของระบบทั้งหมด หากไม่ได้ตั้งค่าเงื่อนไขเริ่มต้นเหล่านี้อย่างถูกต้อง การทดสอบจะไม่สามารถทดสอบโค้ดในบริบทที่สมจริง ซึ่งจะลดคุณค่าและความแม่นยำของผลลัพธ์การทดสอบหน่วย[ 29 ]
ต้องอาศัยวินัยตลอดกระบวนการพัฒนา
เพื่อให้ได้ประโยชน์ตามที่ตั้งใจไว้จากการทดสอบหน่วย จำเป็นต้องมีวินัยที่เข้มงวดตลอดกระบวนการพัฒนาซอฟต์แวร์
ต้องใช้ระบบควบคุมเวอร์ชัน
จำเป็นอย่างยิ่งที่จะต้องบันทึกรายละเอียดอย่างรอบคอบ ไม่เพียงแต่การทดสอบที่ได้ดำเนินการไปแล้วเท่านั้น แต่ยังรวมถึงการเปลี่ยนแปลงทั้งหมดที่เกิดขึ้นกับซอร์สโค้ดของหน่วยนี้หรือหน่วยอื่นๆ ในซอฟต์แวร์ด้วย การใช้ ระบบ ควบคุมเวอร์ชันจึงเป็นสิ่งจำเป็น หากเวอร์ชันต่อมาของหน่วยนั้นไม่ผ่านการทดสอบใดๆ ที่เคยผ่านมาก่อน ซอฟต์แวร์ควบคุมเวอร์ชันสามารถแสดงรายการการเปลี่ยนแปลงซอร์สโค้ด (ถ้ามี) ที่ได้นำไปใช้กับหน่วยนั้นตั้งแต่เวลานั้นเป็นต้นมา
จำเป็นต้องมีการตรวจสอบอย่างสม่ำเสมอ
นอกจากนี้ การนำกระบวนการที่ยั่งยืนมาใช้เพื่อให้แน่ใจว่าความล้มเหลวของกรณีทดสอบจะได้รับการตรวจสอบอย่างสม่ำเสมอและแก้ไขทันทีก็เป็นสิ่งจำเป็นเช่นกัน[ 30 ]หากไม่ได้นำกระบวนการดังกล่าวมาใช้และฝังแน่นอยู่ในขั้นตอนการทำงานของทีม แอปพลิเคชันจะพัฒนาไปไม่สอดคล้องกับชุดทดสอบหน่วย ทำให้เกิดผลลัพธ์ที่เป็นเท็จมากขึ้นและลดประสิทธิภาพของชุดทดสอบ
ข้อจำกัดสำหรับซอฟต์แวร์ระบบฝังตัว
การทดสอบหน่วยของซอฟต์แวร์ระบบฝังตัวก่อให้เกิดความท้าทาย เนื่องจากซอฟต์แวร์กำลังได้รับการพัฒนาบนแพลตฟอร์มที่แตกต่างจากแพลตฟอร์มที่จะใช้งานจริง ทำให้ยากที่จะเรียกใช้โปรแกรมทดสอบในสภาพแวดล้อมการใช้งานจริง เช่นเดียวกับโปรแกรมเดสก์ท็อป[ 31 ]
ข้อจำกัดในการทดสอบการทำงานร่วมกับระบบภายนอก
การทดสอบหน่วยมักจะง่ายที่สุดเมื่อเมธอดมีพารามิเตอร์อินพุตและเอาต์พุตบางอย่าง การสร้างการทดสอบหน่วยจะไม่ใช่เรื่องง่ายนักเมื่อหน้าที่หลักของเมธอดคือการโต้ตอบกับสิ่งภายนอกแอปพลิเคชัน ตัวอย่างเช่น เมธอดที่จะทำงานกับฐานข้อมูลอาจต้องสร้างแบบจำลองการโต้ตอบกับฐานข้อมูล ซึ่งอาจจะไม่ครอบคลุมเท่ากับการโต้ตอบกับฐานข้อมูลจริง[ 32 ]
ตัวอย่าง
JUnit
ด้านล่างนี้คือตัวอย่างชุดทดสอบ JUnit ซึ่งเน้นที่Adderคลาส
คลาสAdder { public int add ( int a , int b ) { return a + b ; } }ชุดทดสอบใช้ คำสั่ง assertเพื่อตรวจสอบผลลัพธ์ที่คาดหวังของค่าอินพุตต่างๆ ที่ป้อนเข้าสู่sumเมธอด
import static org.junit.Assert.assertEquals ; import org.junit.Test ; public class AdderUnitTest { @Test public void sumReturnsZeroForZeroInput ( ) { Adder adder = new Adder (); assertEquals ( 0 , adder.add ( 0 , 0 ) ); } }@Test public void sumReturnsSumOfTwoPositiveNumbers () { Adder adder = new Adder (); assertEquals ( 3 , adder . add ( 1 , 2 )); }@Test public void sumReturnsSumOfTwoNegativeNumbers () { Adder adder = new Adder (); assertEquals ( - 3 , adder . add ( - 1 , - 2 )); }@Test public void sumReturnsSumOfLargeNumbers () { Adder adder = new Adder (); assertEquals ( 2222 , adder . add ( 1234 , 988 )); } }ในฐานะข้อกำหนดที่สามารถดำเนินการได้
การใช้ unit-test เป็นข้อกำหนดในการออกแบบมีข้อดีที่สำคัญอย่างหนึ่งเหนือกว่าวิธีการออกแบบอื่นๆ คือ เอกสารการออกแบบ (ซึ่งก็คือ unit-test นั่นเอง) สามารถนำมาใช้ตรวจสอบการใช้งานได้จริง การทดสอบจะไม่ผ่านเลยหากนักพัฒนาไม่ได้นำโซลูชันไปใช้ตามที่ออกแบบไว้
การทดสอบหน่วยขาดความสามารถในการเข้าถึงบางส่วนของข้อกำหนดเชิงแผนภาพ เช่น แผนภาพ UMLแต่สามารถสร้างได้จากการทดสอบหน่วยโดยใช้เครื่องมืออัตโนมัติ ภาษาโปรแกรมสมัยใหม่ส่วนใหญ่มีเครื่องมือฟรี (โดยปกติจะมีให้ใช้งานเป็นส่วนขยายของIDE ) เครื่องมือฟรี เช่น เครื่องมือที่ใช้ เฟรมเวิร์ก xUnitจะมอบหมายการแสดงผลกราฟิกให้กับระบบอื่นเพื่อให้มนุษย์สามารถใช้งานได้[ 33 ]
แอปพลิเคชัน
การเขียนโปรแกรมแบบสุดขั้ว
การทดสอบหน่วย (Unit testing) เป็นหัวใจสำคัญของการเขียนโปรแกรมแบบสุดขั้ว (Extreme programming ) ซึ่งอาศัยเฟรมเวิร์กการทดสอบหน่วย อัตโนมัติ เฟรมเวิร์กการทดสอบหน่วยอัตโนมัตินี้อาจเป็นเฟรมเวิร์กจากภายนอก เช่นxUnitหรืออาจสร้างขึ้นภายในกลุ่มนักพัฒนาเอง
การเขียนโปรแกรมแบบ Extreme Programming ใช้การสร้าง Unit Test สำหรับการพัฒนาแบบ Test-Driven Development (TDD ) นักพัฒนาเขียน Unit Test ที่เปิดเผยข้อกำหนดของซอฟต์แวร์หรือข้อบกพร่อง การทดสอบนี้จะล้มเหลวเนื่องจากข้อกำหนดนั้นยังไม่ได้ถูกนำไปใช้ หรือเพราะมันจงใจเปิดเผยข้อบกพร่องในโค้ดที่มีอยู่ จากนั้น นักพัฒนาจะเขียนโค้ดที่ง่ายที่สุดเพื่อให้การทดสอบนั้น รวมถึงการทดสอบอื่นๆ ผ่านทั้งหมด
โค้ดส่วนใหญ่ในระบบจะถูกทดสอบแบบหน่วย แต่ไม่จำเป็นต้องทดสอบทุกเส้นทางในโค้ด การเขียนโปรแกรมแบบสุดขั้วกำหนดกลยุทธ์ "ทดสอบทุกอย่างที่อาจเกิดข้อผิดพลาดได้" มากกว่าวิธีการแบบดั้งเดิมที่ "ทดสอบทุกเส้นทางการทำงาน" ซึ่งนำไปสู่การที่นักพัฒนาสร้างการทดสอบน้อยลงกว่าวิธีการแบบคลาสสิก แต่นี่ไม่ใช่ปัญหา เพียงแต่เป็นการกล่าวซ้ำข้อเท็จจริง เนื่องจากวิธีการแบบคลาสสิกนั้นแทบจะไม่เคยถูกปฏิบัติตามอย่างเป็นระบบเพียงพอที่จะทดสอบทุกเส้นทางการทำงานอย่างละเอียดถี่ถ้วน[ 34 ]การเขียนโปรแกรมแบบสุดขั้วเพียงแค่ยอมรับว่าการทดสอบนั้นแทบจะไม่ครอบคลุมทั้งหมด (เพราะมักจะมีราคาแพงและใช้เวลานานเกินกว่าจะคุ้มค่าทางเศรษฐกิจ) และให้คำแนะนำเกี่ยวกับวิธีการมุ่งเน้นทรัพยากรที่มีจำกัดอย่างมีประสิทธิภาพ
ที่สำคัญคือ โค้ดทดสอบถือเป็นส่วนประกอบสำคัญของโปรเจ็กต์ เนื่องจากได้รับการดูแลรักษาให้มีคุณภาพเทียบเท่ากับโค้ดที่ใช้งานจริง โดยได้กำจัดส่วนที่ซ้ำซ้อนออกไปทั้งหมด นักพัฒนาจะเผยแพร่โค้ดทดสอบหน่วยไปยังที่เก็บโค้ดพร้อมกับโค้ดที่ต้องการทดสอบ การทดสอบหน่วยอย่างละเอียดถี่ถ้วนของ Extreme Programming ช่วยให้ได้รับประโยชน์ดังที่กล่าวมาข้างต้น เช่น การพัฒนาและปรับโครงสร้าง โค้ดที่ง่ายขึ้นและมั่นใจมากขึ้น การรวมโค้ดที่ง่ายขึ้น เอกสารประกอบที่ถูกต้อง และการออกแบบที่เป็นโมดูลมากขึ้น การทดสอบหน่วยเหล่านี้ยังถูกเรียกใช้อย่างต่อเนื่องในรูปแบบของการทดสอบการถดถอยอีก ด้วย
การทดสอบหน่วยยังมีความสำคัญต่อแนวคิดของการออกแบบที่เกิดขึ้นเอง (Emergent Design)ซึ่งพัฒนาการออกแบบซอฟต์แวร์แบบวนซ้ำผ่าน วงจร การพัฒนาแบบทดสอบนำโดยการเขียนการทดสอบหน่วย ทำให้ผ่านการทดสอบ และทำการปรับโครงสร้างใหม่ การทดสอบหน่วยเป็นเครือข่ายความปลอดภัยในการถดถอยที่ทำให้การปรับโครงสร้างใหม่อย่างต่อเนื่องมีความปลอดภัย[ 35 ]
เฟรมเวิร์กการทดสอบอัตโนมัติ
เฟรมเวิร์กสำหรับการทดสอบอัตโนมัติมีคุณสมบัติสำหรับการดำเนินการทดสอบโดยอัตโนมัติ และสามารถเร่งความเร็วในการเขียนและเรียกใช้การทดสอบได้ เฟรมเวิร์กเหล่านี้ได้รับการพัฒนาขึ้นสำหรับภาษา โปรแกรมที่หลากหลาย
โดยทั่วไป เฟรมเวิร์กเป็นซอฟต์แวร์จากภายนอกไม่ได้รวมอยู่ในชุดคอมไพเลอร์หรือสภาพแวดล้อมการพัฒนาแบบบูรณาการ (IDE)
สามารถเขียนการทดสอบได้โดยไม่ต้องใช้เฟรมเวิร์กเพื่อทดสอบโค้ดที่กำลังทดสอบโดยใช้การยืนยันการจัดการข้อยกเว้นและ กลไก การควบคุมการไหล อื่นๆ เพื่อตรวจสอบพฤติกรรมและรายงานความล้มเหลว บางคนตั้งข้อสังเกตว่าการทดสอบโดยไม่ใช้เฟรมเวิร์กมีคุณค่าเนื่องจากมีอุปสรรคในการนำเฟรมเวิร์กมาใช้ และการมีการทดสอบบ้างก็ดีกว่าไม่มีเลย แต่เมื่อมีเฟรมเวิร์กแล้ว การเพิ่มการทดสอบก็จะง่ายขึ้น[ 36 ]
ในบางเฟรมเวิร์ก ฟีเจอร์การทดสอบขั้นสูงจะขาดหายไปและต้องเขียนโค้ดด้วยตนเอง
การสนับสนุนการทดสอบหน่วยระดับภาษา
ภาษาโปรแกรมบางภาษาให้การสนับสนุนการทดสอบหน่วยโดยตรง ไวยากรณ์ของภาษาเหล่านั้นอนุญาตให้ประกาศการทดสอบหน่วยได้โดยตรงโดยไม่ต้องนำเข้าไลบรารี (ไม่ว่าจะเป็นไลบรารีของบุคคลที่สามหรือไลบรารีมาตรฐาน) นอกจากนี้ เงื่อนไขบูลีนของการทดสอบหน่วยยังสามารถแสดงได้ในไวยากรณ์เดียวกันกับนิพจน์บูลีนที่ใช้ในโค้ดที่ไม่ใช่การทดสอบหน่วย เช่นเดียวกับที่ใช้ในคำสั่ง `for` ifและwhile`for`
ภาษาโปรแกรมที่มีระบบรองรับการทดสอบหน่วยในตัว ได้แก่:
ภาษาโปรแกรมที่มีเฟรมเวิร์กสำหรับการทดสอบหน่วยมาตรฐาน ได้แก่:
บางภาษาไม่มีระบบรองรับการทดสอบหน่วย (unit testing) ในตัว แต่มีไลบรารีหรือเฟรมเวิร์กสำหรับการทดสอบหน่วยอยู่แล้ว ภาษาเหล่านั้นได้แก่:
- เอบีเอพี
- ซี++
- ซี#
- โคลจูร์[ 46 ]
- ยาอายุวัฒนะ
- ชวา
- สคริปต์
- ออบเจกทีฟซี
- เพิร์ล
- พีพี
- พาวเวอร์เชลล์[ 47 ]
- Rกับการทดสอบนั้น
- สกาล่า
- ทีซีแอล
- Visual Basic .NET
- Xojoร่วมกับ XojoUnit
ดูเพิ่มเติม
- การทดสอบการยอมรับ
- การทดสอบลักษณะเฉพาะ
- การทดสอบการใช้งานโดยอิงตามส่วนประกอบ
- หลักเกณฑ์การออกแบบ
- ออกแบบตามสัญญา
- การเขียนโปรแกรมแบบสุดขั้ว
- การทดสอบการทำงาน
- การทดสอบการบูรณาการ
- รายชื่อเฟรมเวิร์กสำหรับการทดสอบหน่วย
- การทดสอบการถดถอย
- โบราณคดีซอฟต์แวร์
- การทดสอบซอฟต์แวร์
- การทดสอบระบบ
- กรณีทดสอบ
- การพัฒนาแบบทดสอบนำ
- xUnit – ตระกูลของเฟรมเวิร์กสำหรับการทดสอบหน่วย (Unit Testing)
อ่านเพิ่มเติม
- Feathers, Michael C. (2005). การทำงานอย่างมีประสิทธิภาพกับรหัสเดิม . Upper Saddle River, NJ: Prentice Hall Professional Technical Reference. ISBN 978-0131177055.
- Gulati, Shekhar; Sharma, Rahul (2017). การทดสอบหน่วยด้วย Java โดยใช้ JUnit 5. Apress .
ลิงก์ภายนอก
- การพัฒนาแบบทดสอบนำ (จากวิกิของ Ward Cunningham)
สรุปเนื้อหา
ข้อมูลสำคัญจากบทความ
ข้อมูลสำคัญเกี่ยวกับ การทดสอบหน่วย
การทดสอบหน่วยหรือที่เรียกว่า การทดสอบ ส่วนประกอบหรือโมดูลเป็นรูปแบบหนึ่งของการทดสอบซอฟต์แวร์โดย การทดสอบ ซอร์สโค้ด ที่แยกออกมา เพื่อตรวจสอบพฤติกรรมที่คาดหวัง
ประวัติศาสตร์
การทดสอบหน่วย (Unit testing) ซึ่งเป็นหลักการสำหรับการทดสอบส่วนย่อยของระบบซอฟต์แวร์ขนาดใหญ่แยกกัน มีมาตั้งแต่ยุคแรกเริ่มของวิศวกรรมซอฟต์แวร์ ในเดือนมิถุนายน พ.ศ. 2499 ในงานสัมมนาเรื่องวิธีการเขียนโปรแกรมขั้นสูงสำหรับคอมพิวเตอร์ดิจิทัลของกองทัพเรือสหรัฐฯ
หน่วย
หน่วยถูกกำหนดให้เป็นพฤติกรรมเดียวที่แสดงโดยระบบที่กำลังทดสอบ (SUT) ซึ่งโดยปกติจะสอดคล้องกับข้อกำหนด ในขณะที่หน่วยอาจสอดคล้องกับฟังก์ชันหรือโมดูลเดียว (ใน การเขียนโปรแกรมเชิงกระบวนการ ) หรือเมธอดหรือคลาสเดียว (ใน การเขียนโปรแกรมเชิงวัตถุ )...
การประหารชีวิต
การทดสอบหน่วยสามารถทำได้ด้วยตนเองหรือโดย การดำเนินการ ทดสอบอัตโนมัติ การทดสอบอัตโนมัติมีข้อดีหลายประการ เช่น การทดสอบบ่อยครั้ง การทดสอบโดยไม่ต้องเสียค่าใช้จ่ายด้านบุคลากร และการทดสอบที่สม่ำเสมอและทำซ้ำได้