具有依赖关系的对象的单元测试工厂方法

时间:2014-12-10 12:08:58

标签: c# unit-testing

我是单元测试的新手。

由于可维护性原因,建议使用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可能不是很好的本地默认值。 (我知道 - 我们通常对记录器有很好的默认值,但它可能是另一个依赖项)

我考虑了工厂方法的可选参数。但似乎有逻辑。这很简单,但仍然是逻辑。

有什么好方法可以解决这个问题吗?或者它已经足够好了,在我们需要的时候在课堂上创建实例是一种常见的情况吗?

1 个答案:

答案 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.");
}