Ian*_*ton 3 integration-testing unit-testing ioc-container
在解析某些接口时,我有一个IoC容器做一些复杂的对象构造.我想在我的单元/集成测试中使用这些接口的实现.在使用IoC容器的测试中解析这些接口是否有任何问题,或者在这种情况下是否应该手动构建实例?
当我们对一个班级进行单元测试时,我们关心的是"班级是否按照我们的意愿行事".我们的出发点是一个完全构建的实例; 我们如何到达那里不是一个单元测试问题,虽然它可能被认为是一个集成测试问题.
说我们有,
A
A(IB b, IC c)
B : IB
B(ID d)
C : IC
D : ID
Run Code Online (Sandbox Code Playgroud)
当单元测试A时,B使用ID的事实应该没有实际意义(如果不是那么我们应该看看我们的接口.有一个访问IB.D.xxx是不好的),我们需要做的就是提供A和一些IB和IC的实施(模拟/存根).
就A的单元测试而言,A实例是手工创建还是由容器创建并不重要.无论哪种方式我们得到相同的对象.
只要我们将mocks作为第一级依赖项传递,那么在使用容器而不是手动创建对象时就没有保存.只有在我们使用IOC创建对象图时才会进行保存,但如果我们这样做,那么我们就会进行集成测试.这不是一件坏事,但我们需要明确我们的目标.
当我们进行单元测试时,我们会为其进行单元测试
D C B(传入模拟/存根ID)A(传入模拟/存根IC和IB)
当单元测试A时,我们不需要D的正确答案通过B到A.
我们关心的是A中的逻辑按预期工作,例如,A用参数y和z调用IB.x()并返回IB.x()的结果.如果我们检查我们得到了正确的答案(比如,一个依赖于D中的逻辑的答案),那么我们已经过单元测试并进入集成测试.
底线 只要我们正确隔离
被测单元,被测单元是否由IOC容器或手工创建并不重要.如果我们使用容器来创建一个对象图,那么我们进入集成测试的好几率(和/或在类之间有太多耦合的问题 - 调用IB.D.xxx)
模拟集成测试
警告:以下部分内容取决于正在使用的IOC容器.使用Unity时,最后一次注册"获胜".我不知道这适用于其他人.
在我们所讨论的极简主义制度中
AA(IB b)
B:IB
B是我们的"叶子".它与外界交谈(例如,从网络流中读取).在进行Integration测试时,我们想要模拟这个.
对于实时系统,我们使用CreateContainerCore()设置ServiceLocator.这包括注册IB的"实时"实施.
在执行需要模拟IB版本的集成测试时,我们使用CreateContainerWithMockedExternalDependencies()设置容器,该包装包含CreateContainerCore()并为IB注册模拟对象.
下面的代码大大简化,但形状扩展到所需的类和依赖项.在实践中,我们有一个基本测试类,它有助于设置服务定位器,模拟/存根类,访问模拟以进行验证和其他内容保存(例如,每个测试不需要显式设置ServiceLocator提供程序)
[TestClass]
public class IocIntegrationSetupFixture {
[TestMethod]
public void MockedB() {
ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(CreateContainerWithMockedExternalDependencies()));
var a = ServiceLocator.Current.GetInstance<A>();
Assert.AreEqual("Mocked B", a.GetMessage());
}
[TestMethod]
public void LiveB() {
ServiceLocator.SetLocatorProvider(() => new UnityServiceLocator(CreateContainerCore()));
var a = ServiceLocator.Current.GetInstance<A>();
Assert.AreEqual("Live B", a.GetMessage());
}
private IUnityContainer CreateContainerCore() {
var container = new UnityContainer();
container.RegisterType<IB, B>(new ContainerControlledLifetimeManager());
return container;
}
private IUnityContainer CreateContainerWithMockedExternalDependencies() {
var container = CreateContainerCore();
var mockedB = new Mock<IB>();
mockedB.SetupGet(mk => mk.Message).Returns("Mocked B");
container.RegisterInstance<IB>(mockedB.Object);
return container;
}
public class A {
private IB _b;
public A(IB b) {
_b = b;
}
public string GetMessage() {
return _b.Message;
}
}
public interface IB {
string Message { get; }
}
private class B : IB {
public string Message {
get { return "Live B"; }
}
}
}
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
1426 次 |
最近记录: |