我是单元测试的新手。
由于可维护性原因,建议使用Factory方法创建测试类的实例。
喜欢:
public class StringCalculatorTests
{
[Fact]
public void Add_EmptyString_ReturnZero()
{
var calculator = CreateCalculator();
int result = calculator.Add("");
result.Should().Be(0);
}
private static StringCalculator CreateCalculator()
{
//Some difficult object creation
var logger = Substitute.For<ILogger>();
var calculator = new StringCalculator(logger);
calculator.Initialize();
return calculator;
}
}
一切都很好:如果API发生变化 - 我只会在一个地方改变StringCalculator的创建,而不是每次测试都会改变。
但是,如果我需要更改某些ILogger
方法的返回值,该怎么办?或者我会将ILogger
用作存根,而不是模拟:
[Fact]
public void Add_EmptyString_LogAboutEmptyInput()
{
var loggerMock = Substitute.For<ILogger>();
var calculator = new StringCalculator(loggerMock);
calculator.Initialize();
calculator.Add("");
logger.Received("Empty input.");
}
现在我不能使用工厂方法,如果API有变化 - 我应该通过我的测试来改变它。
我考虑过属性注入 - 但例如ILogger可能不是很好的本地默认值。 (我知道 - 我们通常对记录器有很好的默认值,但它可能是另一个依赖项)
我考虑了工厂方法的可选参数。但似乎有逻辑。这很简单,但仍然是逻辑。
有什么好方法可以解决这个问题吗?或者它已经足够好了,在我们需要的时候在课堂上创建实例是一种常见的情况吗?
答案 0 :(得分:0)
您可以重载工厂方法以接受模拟记录器。
private static StringCalculator CreateCalculator(ILogger logger)
{
var calculator = new StringCalculator(logger);
calculator.Initialize();
return calculator;
}
然后您可以在测试中创建模拟记录器(如果在多个测试中使用相同的模拟,则可能是记录器的单独工厂方法)
[Fact]
public void Add_EmptyString_LogAboutEmptyInput()
{
var loggerMock = //whatever code you need to set up your mock
var calculator = CreateCalculator(loggerMock);
calculator.Add("");
logger.Received("Empty input.");
}