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

本文关键字:单元测试 工厂 方法 对象 依赖 | 更新日期: 2023-09-27 18:33:45

我是单元测试的新手。

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

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

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

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

您可以重载工厂方法以接受模拟记录器。

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