การฉีดแบบพึ่งพานั้นเป็นสิ่งจำเป็นสำหรับการทดสอบหน่วยหรือไม่?


55

การใช้การฉีดพึ่งพา (DI) จำเป็นสำหรับการทดสอบหน่วยหรือไม่

ฉันไม่สามารถคิดวิธีอื่นในการแยกรหัสเพื่อให้สามารถทดสอบได้ นอกจากนี้ตัวอย่างทั้งหมดที่ฉันเคยเห็นใช้รูปแบบนี้ นั่นเป็นเพราะมันเป็นทางเลือกเดียวที่ทำงานได้หรือมีทางเลือกอื่น ๆ ?


5
การพึ่งพาการฉีดไม่จำเป็น แต่แนวคิดที่กว้างขึ้นของการกลับกันของการควบคุมคือ
Jeremy Heiler

มีบางอย่างที่จะกล่าวถึงในระดับนี้ หากฉันมีฐานรหัสขนาดเล็กที่มีเลเยอร์น้อยมากดังนั้น DI อาจไม่มีประโยชน์
JB King

@JBKing ถ้าคุณมีฐานรหัสขนาดเล็กที่คุณไม่จำเป็นต้องชั้นหรือการทดสอบหน่วย
Sklivvz

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

คำตอบ:


42

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

ฉันเองเคยใช้อินเทอร์เฟซและโรงงานมาก่อนเรียนรู้เกี่ยวกับ DI ชื่อคลาสจริงจากโรงงานอาจถูกอ่านจากไฟล์ปรับแต่งหรือส่งผ่านไปยัง SUT เพื่อเป็นอาร์กิวเมนต์

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

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


เห็นด้วย DI เป็นประโยชน์อย่างยิ่งสำหรับการเยาะเย้ยวัตถุ แต่มีหลายสถานการณ์ที่ DI ไม่มีประโยชน์ในการทดสอบ
Kemoda

@Kemoda ชอบอะไรนะ?
BЈовић

@VJovic ตัวอย่างเช่นวัตถุแบบสแตนด์อโลน ฉันคิดว่าวิธีการที่ใช้อาร์กิวเมนต์บางอย่างและดำเนินการบางอย่าง แต่ไม่ได้ขึ้นอยู่กับองค์ประกอบอื่น (จึงไม่จำเป็นต้อง DI)
Kemoda

@Kemoda ดูเหมือนว่าคุณกำลังอธิบายถึงการเขียนโปรแกรมที่ใช้งานได้และคุณกำลังใช้ DI คุณกำลังฉีดการพึ่งพาของคุณเป็นพารามิเตอร์วิธีการ
Erik Dietrich

3
@huggie ทำไมรายละเอียดการใช้งานจึงรั่วไหลออกมาที่นี่ โดยทั่วไปแล้วการพึ่งพาการฉีดจะถูกซ่อนอยู่หลังอินเทอร์เฟซและจุดทั้งหมดคือคลาสไคลเอนต์ไม่มีความคิด - และไม่เกี่ยวข้อง - ไม่ว่าการใช้งานจริงของการพึ่งพานี้เป็นคลาสการผลิตจริงหรือจำลอง การสร้างอินสแตนซ์เกิดขึ้นนอกคลาสไคลเอนต์มันจะเห็นอินสแตนซ์สำเร็จรูปเท่านั้น
PéterTörök

56

การแยกตัวเป็นสิ่งจำเป็นสำหรับการทดสอบหน่วย DI เป็นวิธีที่ดีในการบรรลุการแยกส่วน


17
คำแถลงที่เป็นจริงซึ่งไม่สามารถตอบคำถามได้
เทรวิส

10

คุณสามารถแยกการพึ่งพาได้โดยไม่ต้องใช้ DI ทั้งนี้ขึ้นอยู่กับเทคโนโลยีที่คุณใช้ ตัวอย่างเช่นในโลก. NET โมลช่วยให้คุณสามารถแยกการพึ่งพาโดยไม่มีรูปแบบ DI

ที่กล่าวว่าฉันเชื่อว่ากรอบการแยกเหล่านี้ถูกเขียนและมีไว้สำหรับสถานการณ์ในรหัสของคุณที่มีการอ้างอิงภายนอก (ระบบไฟล์ฐานข้อมูล ฯลฯ ) นั่นคือความจริงที่ว่าคน ๆ หนึ่งสามารถทำได้ไม่ได้หมายความว่าเขาหรือเธอควรจะทำ

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


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

@ ไวแอตบาร์เน็ตต์ใช่จริงมาก ไฝมีความสามารถในการโน้มน้าวใจให้ใครบางคนพูดว่า "ใครต้องการความแตกต่างนี้ทั้งหมดและเปิด / ปิดเรื่องใช่ไหม?!?"
Erik Dietrich

1
ไฝถูกแทนที่ด้วยfakesและจากหน้า fakes "กรอบ Fakes ช่วยให้นักพัฒนาสร้างรักษาและฉีดการใช้งานหุ่นจำลองในการทดสอบหน่วยของพวกเขา" ฟังดูเหมือน DI กับฉัน
ลงชื่อ

1
@ ลงชื่อเข้าใช้ลิงก์ของคุณยังกล่าวอีกว่า "กรอบการทำงานของ Fakes สามารถใช้ในการควบคุมวิธีการใด ๆ ของ. NET รวมถึงวิธีที่ไม่เสมือนและแบบคงที่ในรูปแบบที่ปิดผนึก" ความจริงที่ว่ากรอบการแยกสามารถใช้ร่วมกับ DI ไม่ได้หมายความว่ามันเป็น DI
Erik Dietrich

4

ไม่ DI ไม่จำเป็นสำหรับการทดสอบหน่วย แต่ช่วยได้มาก

คุณสามารถใช้โรงงานหรือตัวระบุตำแหน่งและทดสอบตามที่คุณต้องการกับ DI (ไม่สวยงามและต้องมีการตั้งค่าเพิ่มเติม)

นอกจากนี้Mock Objectsจะมีความสำคัญในระบบเดิมที่การโทรจำนวนมากถูกมอบหมายให้ทำงานแทนการพึ่งพา (วัตถุจำลองสามารถนำไปใช้อย่างกว้างขวางในการตั้งค่าที่เหมาะสมเช่นกัน)

อาจมีการตั้งค่าที่การทดสอบแทบจะเป็นไปไม่ได้ แต่นี่ไม่ได้ขึ้นอยู่กับว่าจะใช้การฉีดแบบพึ่งพาหรือไม่


3

ไม่มีการฉีดพึ่งพาไม่ได้เป็นสิ่งจำเป็นสำหรับการทดสอบหน่วย

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

ตัวอย่าง (ใช้ DI) การใช้งานนี้ขึ้นอยู่กับพนักงานบัญชี ...

 bool hasPermissionToTransferMoney(Employee employee, Account from, Account to, Money amount)
 {
     if (amount > 100 && employee.isStudent())
        return false;
     if (to.getOwner().getFamiliyName() == employee.getFamilyName() && ...
        return false; // cannot transfer money to himself;
     ...
 }

หลังจากแยกการรวบรวมข้อมูลและการคำนวณ:

 bool hasPermissionToTransferMoney(Employee employee, Account from, Account to, Money amount)
 {
     return hasPermissionToTransferMoney(employee.isStudent(), employee.getFamilyName(), to.getOwner().getFamilyName(), ...);
 }

 // the actual permission calculation
 static bool hasPermissionToTransferMoney(boolean isStudent, string employeeFamilyName, string receiverFamilyName, ...)
     if (amount > 100 && isStudent)
        return false;
     if (receiverFamilyName == employeeFamiliyName && ...
        return false; // cannot transfer money to himself
     ...
 }

ส่วนการคำนวณสามารถทดสอบได้ง่ายโดยไม่ต้องพึ่งพาการฉีด


1
  • การฉีดพึ่งพาไม่จำเป็นสำหรับการทดสอบหน่วย

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


0

ใช่มีทางเลือกอื่นสำหรับการใช้ DI สำหรับการแยก

ทางเลือกหนึ่งคือใช้โรงงานหรือ ServiceLocator ซึ่งสามารถกำหนดค่าจากการทดสอบเพื่อส่งคืนวัตถุจำลองแทนวัตถุจริง

อีกประการหนึ่งคือการใช้กรอบการแยกที่เหมาะสมหรือเครื่องมือเยาะเย้ย มีเครื่องมือดังกล่าวสำหรับภาษาการเขียนโปรแกรมที่ทันสมัยทุกภาษา (สำหรับ Java, C #, Ruby และ Python อย่างน้อย) พวกเขาสามารถแยกคลาสที่ถูกทดสอบจากการใช้คลาส / ประเภทอื่น ๆ แม้ว่าคลาสที่ทดสอบโดยตรงจะสร้างการพึ่งพาได้ทันที

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