หน่วยการทดสอบส่วนประกอบภายใน


14

คุณทำการทดสอบส่วนประกอบภายใน / ส่วนตัวของคลาส / โมดูล / แพ็คเกจ / ฯลฯ ในระดับใด คุณทดสอบพวกเขาทั้งหมดหรือคุณเพียงแค่ทดสอบส่วนต่อประสานกับโลกภายนอก? ตัวอย่างของภายในเหล่านี้เป็นวิธีการส่วนตัว

ยกตัวอย่างเช่นลองนึกภาพตัวแยกวิเคราะห์แบบสืบเชื้อสายซ้ำซึ่งมีโพรซีเดอร์ภายใน (ฟังก์ชัน / เมธอด) หลายตัวที่เรียกใช้จากโพรซีเดอร์กลางเดียว อินเทอร์เฟซเดียวกับโลกภายนอกคือโพรซีเดอร์กลางซึ่งใช้สตริงและส่งคืนข้อมูลที่ถูกวิเคราะห์คำ โพรซีเดอร์อื่นแยกวิเคราะห์ส่วนต่าง ๆ ของสตริงและถูกเรียกจากโพรซีเดอร์กลางหรือโพรซีเดอร์อื่น

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

ฉันสามารถคิดถึงข้อโต้แย้งบางอย่าง:

ข้อดี :

  1. การทดสอบเพิ่มเติมดีกว่าเสมอและสิ่งนี้สามารถช่วยเพิ่มความครอบคลุมรหัสได้
  2. ส่วนประกอบภายในบางอย่างอาจยากที่จะให้อินพุตที่เฉพาะเจาะจง (ตัวอย่างเช่น edge edge) โดยให้อินพุตกับอินเตอร์เฟสภายนอก
  3. การทดสอบที่ชัดเจนยิ่งขึ้น หากส่วนประกอบภายในมีข้อบกพร่อง (คงที่) กรณีทดสอบสำหรับองค์ประกอบนั้นจะทำให้ชัดเจนว่าข้อผิดพลาดนั้นอยู่ในองค์ประกอบเฉพาะนั้น

ข้อเสีย :

  1. การเปลี่ยนโครงสร้างจะเจ็บปวดเกินไปและใช้เวลานาน หากต้องการเปลี่ยนแปลงอะไรคุณต้องเขียนการทดสอบหน่วยใหม่แม้ว่าผู้ใช้อินเทอร์เฟซภายนอกจะไม่ได้รับผลกระทบ
  2. บางภาษาและกรอบการทดสอบไม่อนุญาต

คุณมีความคิดเห็นอย่างไร?


เป็นไปได้ที่ซ้ำซ้อนหรือทับซ้อนกันอย่างมีนัยสำคัญกับ: programmers.stackexchange.com/questions/10832/…
azheglov

คำตอบ:


8

กรณี: "โมดูล" (ในขอบเขตกว้างนั่นคือบางสิ่งบางอย่างที่มีส่วนต่อประสานสาธารณะและส่วนภายในส่วนตัว) มีตรรกะที่ซับซ้อน / เกี่ยวข้องอยู่ภายใน การทดสอบเพียงอินเทอร์เฟซโมดูลจะเป็นการเรียงลำดับของการทดสอบการรวมที่สัมพันธ์กับโครงสร้างภายในของโมดูลดังนั้นในกรณีที่พบข้อผิดพลาดการทดสอบดังกล่าวจะไม่แปลส่วนภายใน / ส่วนประกอบที่แน่นอนที่รับผิดชอบต่อความล้มเหลว

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

บันทึก:

  • ไม่จำเป็นต้องเปลี่ยนแปลงอะไรในการทดสอบของโมดูล (อดีต) "โมดูลย่อย" เมื่อเปลี่ยนสัญญาของโมดูลเว้นแต่ว่า "โมดูลย่อย" ไม่มีบริการข้อเสนอเพียงพอที่จะปฏิบัติตามสัญญาใหม่ / ที่เปลี่ยนแปลง

  • ไม่มีอะไรที่จะเปิดเผยต่อสาธารณชนโดยไม่จำเป็นเช่นสัญญาของโมดูลจะถูกเก็บไว้และการห่อหุ้มนั้น

[Update]

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

  • เพียงแค่มีรหัสการทดสอบกับเพื่อน (ในเงื่อนไข C ++) หรือแพคเกจ (Java) การเข้าถึงอวัยวะภายในการตั้งค่าสถานะจากภายในและการทดสอบพฤติกรรมตามที่คุณต้องการ

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

และรูปแบบรายการดูเหมือนจะแตกเล็กน้อย (
mlvljr

1
คำตอบที่ดี. ใน. NET คุณสามารถใช้[assembly: InternalsVisibleTo("MyUnitTestAssembly")]คุณสมบัติในAssemblyInfo.csการทดสอบภายใน มันให้ความรู้สึกเหมือนการโกง
ไม่มีใคร

@rmx เมื่อบางสิ่งบางอย่างเป็นไปตามเกณฑ์ที่จำเป็นทั้งหมดมันจะไม่เป็นการโกงแม้ว่าจะมีบางสิ่งที่เหมือนกันกับกลโกงจริง แต่หัวข้อของการเข้าถึง inter- / โมดูลภายในนั้นมีการประดิษฐ์ขึ้นเล็กน้อยในภาษากระแสหลักที่ทันสมัย
mlvljr

2

วิธีการใช้รหัสที่ใช้ FSM นั้นแตกต่างจากที่ใช้แบบดั้งเดิมเล็กน้อย มันคล้ายกับสิ่งที่อธิบายไว้ที่นี่สำหรับการทดสอบฮาร์ดแวร์ (ซึ่งโดยทั่วไปจะเป็น FSM)

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

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


2

ดี - มันขึ้นอยู่กับ :-) หากคุณกำลังติดตาม BDD (การพัฒนาพฤติกรรมขับเคลื่อน) หรือ ATDD (การทดสอบการขับเคลื่อนการทดสอบการตอบรับ) จากนั้นการทดสอบส่วนต่อประสานสาธารณะนั้นใช้ได้ (ตราบใดที่คุณทดสอบอย่างละเอียดด้วยอินพุตที่แตกต่างกัน) การติดตั้งพื้นฐานเช่นวิธีส่วนตัวไม่ใช่ สำคัญจริงๆ

อย่างไรก็ตามสมมติว่าคุณต้องการให้ส่วนหนึ่งของอัลกอริทึมนั้นดำเนินการภายในกรอบเวลาที่กำหนดหรือตามเส้นโค้ง bigO (เช่น nlogn) แล้วใช่การทดสอบแต่ละส่วนมีความสำคัญ บางคนเรียกสิ่งนี้ว่าเป็นวิธีการทดสอบ TDD / หน่วยแบบดั้งเดิม

เช่นเดียวกับทุกสิ่ง YMMV


1

แบ่งออกเป็นหลายส่วนมีความหมายการทำงานเช่นParseQuotedString(), ParseExpression(), ParseStatement(), ParseFile()และทำให้พวกเขาส่วนกลางทั้งหมด มีแนวโน้มว่าไวยากรณ์ของคุณเปลี่ยนแปลงไปอย่างมากจนสิ่งเหล่านี้ไม่เกี่ยวข้อง?


1
วิธีการนี้นำไปสู่การห่อหุ้มที่อ่อนแอกว่าและอินเทอร์เฟซที่ใหญ่กว่าและยากต่อการใช้ / ทำความเข้าใจ
sara
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.