是否有令人信服的理由在单元测试中对没有依赖关系的模块/类使用DI ?

本文关键字:模块 DI 关系 理由 令人信服 单元测试 是否 依赖 | 更新日期: 2023-09-27 18:04:03

依赖注入对于测试有依赖的模块非常有用。这和那些无关。


假设有一些具体的实现,

public class DoesSomething : IDoesSomething 
{
    public int DoesImportant(int x, int y) 
    { 
        // perform some operation 
    }
}

实现这个,

public interface IDoesSomething
{
    int DoesImportant(int x, int y); 
}

在单元测试中,您显然可以在测试中添加new

[TestMethod]
public void DoesSomething_CanDoDoesImportant()
{ 
    int expected = 42; 
    IDoesSomething foo = new DoesSomething(); 
    int actual = foo.DoesImportant(21, 2); 
    Assert.AreEqual(expected, actual); 
}

或者使用DI(这里是自动的,但对问题的原则来说不重要),

[TestMethod]
public void DoesSomething_CanDoDoesImportant()
{
    var builder = new ContainerBuilder();
    builder.RegisterType<DoesSomething>().As<IDoesSomething>();
    var container = builder.Build();
    int expected = 42;
    IDoesSomething foo = container.Resolve<IDoesSomething>();
    int actual = foo.DoesImportant(21, 2);
    Assert.AreEqual(expected, actual);
}

给定这样一个没有依赖关系的独立模块,是否有令人信服的理由将IDoesSomething注入到测试中?或者,是否有令人信服的理由注入IDoesSomething ?

是否有令人信服的理由在单元测试中对没有依赖关系的模块/类使用DI ?

本次测试不需要使用DI容器

这就是为什么可以使用DI容器来解析具体类的原因:所有其他测试都使用类似的模式来通过容器构造类型,而这个测试恰好不需要依赖项。

统一样本:

[TestMethod]
public void DoesSomething_behaves_correctly()
{
     var expected = 42;
     var container = new UnityContainer();
     var foo = container.Resolve<DoesSomething>(); 
     int actual = foo.DoesImportant(21, 21); 
     Assert.AreEqual(expected, actual); 
}
这种方法的附带好处是,当DoesSomething开始具有依赖性时,您的测试需要最小的更改。

您的测试应该专门针对具体的实现编写。

举个例子:

public void DoTestA()
{
    ObjectFactory.Set<IDoesSomething, DoesSomethingBadly>();
    var doesSomething = ObjectFactory.Get<IDoesSomething>();
    Assert.AreEqual(0, doesSomething.Add(1,1));
}
public void DoTestB()
{
    int expected = 42; 
    //This test is now *completely* dependent on DoTestA, and can give different results
    //depending on which test is run first. Further, we don't know
    //which implementation we're testing here. It's not immediately clear, even if
    //there's only one implementation.
    //As its a test, it should be very explicit in what it's testing.
    IDoesSomething foo = ObjectFactory.Get<IDoesSomething>(); 
    int actual = foo.DoesImportant(21, 21); 
    Assert.AreEqual(expected, actual); 
}
// Define other methods and classes here
public class DoesSomething : IDoesSomething 
{
    public int Add(int x, int y) 
    { 
        return x+y;
    }
}
public class DoesSomethingBadly : IDoesSomething
{
    public int Add(int x, int y)
    {
        return x-y;
    }
}
public interface IDoesSomething
{
    int Add(int x, int y); 
}

在测试中,直接引用类绝对是可行的方法。我们不关心它是不是一个接口,我们只关心它的具体实现。

var foo = new DoesSomething();绝对是更好的选择。

IDoesSomething foo = new DoesSomething();是无害的,但它似乎完全没有必要,因为,再一次,我们只关心实现,而不是接口。