是否有令人信服的理由在单元测试中将 DI 与 module/class 一起使用且没有依赖关系?
Is there a compelling reason to use DI with a module/class with no dependencies in a unit test?
依赖注入对于测试具有依赖性的模块非常有用。这与那些无关。
说有具体实现,
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(这里使用 Autofac,但对于问题的原理应该无关紧要),
[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
?
您的测试应该专门针对具体 实现编写。
以此为例:
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);
}
在测试中,直接引用 class 绝对是可行的方法。我们不关心它是一个接口,我们只关心具体的实现。
var foo = new DoesSomething();
绝对是更好的选择。
IDoesSomething foo = new DoesSomething();
没有害处,但似乎完全不需要,因为我们只关心实现,而不关心接口。
本次测试不需要使用 DI 容器。
这里是你可以使用 DI 容器来解析具体的原因 class:所有其他测试都使用类似的模式通过容器构造类型,而这个恰好不需要依赖项。
统一示例:
[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 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(这里使用 Autofac,但对于问题的原理应该无关紧要),
[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
?
您的测试应该专门针对具体 实现编写。
以此为例:
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);
}
在测试中,直接引用 class 绝对是可行的方法。我们不关心它是一个接口,我们只关心具体的实现。
var foo = new DoesSomething();
绝对是更好的选择。
IDoesSomething foo = new DoesSomething();
没有害处,但似乎完全不需要,因为我们只关心实现,而不关心接口。
本次测试不需要使用 DI 容器。
这里是你可以使用 DI 容器来解析具体的原因 class:所有其他测试都使用类似的模式通过容器构造类型,而这个恰好不需要依赖项。
统一示例:
[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
开始具有依赖性时,您的测试只需进行最少的更改。