การใช้ IoC สำหรับการทดสอบหน่วย


97

จะใช้คอนเทนเนอร์ IoC สำหรับการทดสอบหน่วยได้อย่างไร? การจัดการล้อเลียนในโซลูชันขนาดใหญ่ (มากกว่า 50 โครงการ) โดยใช้ IoC มีประโยชน์หรือไม่ ประสบการณ์ใด ๆ ไลบรารี C # ใดที่ใช้งานได้ดีในการทดสอบหน่วย?


7
@Mark Seemann จะถ่อมตัวเกินไปที่จะชี้ให้เห็น แต่ถ้าคุณสนใจคำถามนี้อย่างน้อยคุณควรตระหนักถึงAutoFixture
Ruben Bartelink

1
มีการพูดคุยที่ดีเกี่ยวกับความสัมพันธ์ระหว่าง DI และการล้อเลียนบน Vimeo โดย Miguel Castro: vimeo.com/68390510
GregC

คำตอบ:


131

โดยทั่วไปไม่ควรใช้คอนเทนเนอร์ DI สำหรับการทดสอบหน่วยเนื่องจากการทดสอบหน่วยเป็นการแยกความรับผิดชอบออกจากกัน

พิจารณาคลาสที่ใช้ Constructor Injection

public MyClass(IMyDependency dep) { }

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

คุณสามารถใช้การจำลองแบบไดนามิกเช่น Moq หรือ RhinoMocks เพื่อสร้าง Test Double ได้ แต่ไม่จำเป็นต้องใช้

var dep = new Mock<IMyDependency>().Object;
var sut = new MyClass(dep);

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


13
ตกลง ... เว้นแต่เป้าหมายการทดสอบจะมีคอนเทนเนอร์ IoC เป็นที่พึ่งพาการทดสอบของคุณไม่จำเป็นต้องใช้ ... คุณจะลบกราฟออบเจ็กต์ส่วนใหญ่ออกเมื่อคุณทำการทดสอบหน่วยของคุณ
Anderson Imes

4
@Mark Seemann สิ่งนี้สมเหตุสมผล ... แต่สิ่งที่เกี่ยวกับการทดสอบบูรณาการ? คือฉันเล่นกับการทดสอบ UI และฉันต้องเผชิญกับสถานการณ์เมื่อฉันต้องแชร์รูทองค์ประกอบ มีคำแนะนำอะไรมั้ย?
Arnis Lapsa

5
@Arnis L: สำหรับการทดสอบการรวมนั้นมีความสำคัญน้อยกว่า คุณสามารถเลือกที่จะใช้คอนเทนเนอร์ DI เพื่อวางสายส่วนประกอบ แต่ถ้าเป็นเช่นนั้นคุณมีแนวโน้มที่จะต้องมีการกำหนดค่าสำหรับคอนเทนเนอร์ที่แตกต่างจากแอปพลิเคชันแบบเต็ม - เว้นแต่คุณจะทำการทดสอบใต้ผิวหนังหรือการทดสอบระบบแบบเต็มซึ่งในกรณีนี้ คุณสามารถใช้การกำหนดค่าคอนเทนเนอร์ของแอปพลิเคชันซ้ำได้
Mark Seemann

อ้างอิงถึงนิตยสาร
msdn

18

จะใช้ Ioc Container สำหรับการทดสอบหน่วยได้อย่างไร?

IoC จะบังคับใช้กระบวนทัศน์การเขียนโปรแกรมที่จะทำให้การทดสอบหน่วยแยกกัน (เช่นการใช้ mocks) ง่ายขึ้น: การใช้อินเทอร์เฟซไม่มีใหม่ () ไม่มี singletons ...

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

การจัดการล้อเลียนในโซลูชันขนาดใหญ่ (มากกว่า 50 โครงการ) โดยใช้ IoC มีประโยชน์หรือไม่

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

ประสบการณ์ใด ๆ

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


17

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

พิจารณาสิ่งต่อไปนี้:

[TestFixture]
public class ImageGalleryFixture : ContainerWiredFixture
{
    [Test]
    public void Should_save_image()
    {
        container.ConfigureMockFor<IFileRepository>()
            .Setup(r => r.Create(It.IsAny<IFile>()))
            .Verifiable();

        AddToGallery(new RequestWithRealFile());

        container.VerifyMockFor<IFileRepository>();
    }

    private void AddToGallery(AddBusinessImage request)
    {
        container.Resolve<BusinessPublisher>().Consume(request);
    }
}

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

ส่วนขยายคอนเทนเนอร์จำลองอัตโนมัติมีประโยชน์เมื่อใช้เทคนิคนี้: http://www.agileatwork.com/auto-mocking-unity-container-extension/


8
+1 สำหรับวลี "เช่นการเทซีเมนต์ลงในโค้ดของคุณ" ฉันเริ่มใช้มันมาตลอด
Andrew Shepherd

2

การใช้คอนเทนเนอร์ที่มีความสามารถในการแก้ไขบริการที่ไม่ได้ลงทะเบียน / ไม่รู้จักเช่นSimpleInjector , DryIoc (ของฉัน) สามารถส่งคืน mocks สำหรับส่วนต่อประสานที่ยังไม่ได้ใช้

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

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