MSTest/Simple 注入器:在创建的实例中访问服务引用以模拟其方法之一
MSTest/Simple Injector: access service reference in created instance in order to mock one of its methods
我有 class 取决于服务。我是这样注册的:
container.Register<IMain, Main>();
container.Register<IChild, Child>();
为此 class 编写测试时,我想模拟 IChild 中的一种方法。所以我有 mockIChild.Setup(...等).
但是你不能注册模拟类型,所以我将不得不在测试中手动实例化 Main,对吗?
或者在 Simple Injector 或 MSTest 的深处是否有一些神奇的东西可以做相当于:
[TestMethod]
public void foo()
{
var mockChild = new Mock<IChild>();
var main = container.GetInstance<IMain>(
() => new Mock<IMain>(mockChild));
mockChild.Setup(and so on...)'
}
?
干杯,
.pd.
29-09-17 - 感谢所有提供答案的人。
在进行单元测试时,避免使用 DI 容器来构建被测 class。而是手动构建 class 及其模拟依赖项。
我一年来发现的一个好模式是在测试 class 中使用私有工厂方法,它允许构建被测 class:
private static Main CreateMain(
IChild child = null, ILogger logger = null, IMessageSender sender = null)
{
return new Main(
child: child ?? new Mock<IChild>().Object,
logger: logger ?? new Mock<ILogger>().Object,
messageSender: sender ?? new Mock<IMessageSender>().Object);
}
此工厂方法允许有选择地提供依赖项。任何缺失的依赖项都将自动填充。这样做有以下优点:
- 它避免了每个单元测试都必须自己创建 class 被测对象。这会导致重复代码和噪音。
- 它防止更改 class 测试构造函数导致测试 class 中的每个测试发生变化。如果添加依赖项,则不会更改现有测试;只有工厂方法。
- 单元测试只需定义它明确想要断言的依赖项。这简化了测试,因为它消除了不需要的依赖项的噪声。
- 它允许测试定义自己的模拟依赖项,而不是将所有模拟放在私有字段中,由
Setup
方法实例化。 Setup
方法导致测试逻辑被拆分到多个地方,并导致测试的可读性降低,因为很难看出正在使用哪些依赖项。
工厂方法的用法如下:
public void Test()
{
// Arrange
var child = new Mock<IChild>();
var main = CreateMain(child: child.Object);
// Act
main.DoSomething();
// Assert
Assert.IsTrue(child.ExpectSomethingOnChild);
}
我有 class 取决于服务。我是这样注册的:
container.Register<IMain, Main>();
container.Register<IChild, Child>();
为此 class 编写测试时,我想模拟 IChild 中的一种方法。所以我有 mockIChild.Setup(...等).
但是你不能注册模拟类型,所以我将不得不在测试中手动实例化 Main,对吗?
或者在 Simple Injector 或 MSTest 的深处是否有一些神奇的东西可以做相当于:
[TestMethod]
public void foo()
{
var mockChild = new Mock<IChild>();
var main = container.GetInstance<IMain>(
() => new Mock<IMain>(mockChild));
mockChild.Setup(and so on...)'
}
?
干杯, .pd.
29-09-17 - 感谢所有提供答案的人。
在进行单元测试时,避免使用 DI 容器来构建被测 class。而是手动构建 class 及其模拟依赖项。
我一年来发现的一个好模式是在测试 class 中使用私有工厂方法,它允许构建被测 class:
private static Main CreateMain(
IChild child = null, ILogger logger = null, IMessageSender sender = null)
{
return new Main(
child: child ?? new Mock<IChild>().Object,
logger: logger ?? new Mock<ILogger>().Object,
messageSender: sender ?? new Mock<IMessageSender>().Object);
}
此工厂方法允许有选择地提供依赖项。任何缺失的依赖项都将自动填充。这样做有以下优点:
- 它避免了每个单元测试都必须自己创建 class 被测对象。这会导致重复代码和噪音。
- 它防止更改 class 测试构造函数导致测试 class 中的每个测试发生变化。如果添加依赖项,则不会更改现有测试;只有工厂方法。
- 单元测试只需定义它明确想要断言的依赖项。这简化了测试,因为它消除了不需要的依赖项的噪声。
- 它允许测试定义自己的模拟依赖项,而不是将所有模拟放在私有字段中,由
Setup
方法实例化。Setup
方法导致测试逻辑被拆分到多个地方,并导致测试的可读性降低,因为很难看出正在使用哪些依赖项。
工厂方法的用法如下:
public void Test()
{
// Arrange
var child = new Mock<IChild>();
var main = CreateMain(child: child.Object);
// Act
main.DoSomething();
// Assert
Assert.IsTrue(child.ExpectSomethingOnChild);
}