2

我有各种方法,我想使用 Visual Studio 的 C# 内置单元测试功能进行单元测试。事情进展得很顺利,但我遇到了一个场景,我想“存根”对特定函数调用的依赖。

即,我有一些采用以下格式的方法:

public class ClassWithMethodsIWantToUnitTest 
{
    public void myFcn(object someArg)
    {
        ...
        LoggerService.Instance.LogMessage("myMessage");
        ...
    }
}

所以基本上,我希望我的单元测试能够简单地验证对“LogMessage”的调用是否已经发生。我不想实际检查日志文件或任何东西。我想要一种方法来查看 LoggerService 行是否已被击中并执行。

LoggerService 是一个单例,如果可能的话,我不想仅仅为了单元测试而修改代码。

根据这个问题的格式,在我看来,应该有可能以某种方式控制我的单元测试中的代码。换句话说,有没有办法让我制作一个伪造的 LogMessage 版本,以便我可以将它用于我的单元测试?如果可能的话,我不希望调用“真正的” LogMessage 函数。我只想测试代码是否命中了调用该函数的路径。

这有道理吗?这可能吗?

4

3 回答 3

6

这当然是有道理的,不是一个未知的问题。

不幸的是,您可能需要更改代码,以便它接受依赖注入。也就是说,在测试时,您应该能够注入特制的测试对象(模拟)而不是真实的东西。在您的情况下,这可能意味着能够设置LoggerService.Instance为特殊的模拟对象。

您需要的第二件事是您将测试的假记录器实例。您可能需要一个模拟,这是一个可以设置来检查调用者行为的特殊对象。周围有几个模拟框架,我真的建议你使用一个而不是尝试自己动手。

于 2012-08-18T16:25:38.330 回答
4

Anders 的回答绝对是解决问题的“规范”方式,但在 .NET 4.5 中,还有第二种选择:

假货框架。

它允许您将“假”程序集添加到您的单元测试项目中,该程序集接受委托来代替方法的实际实现。这是一个使用示例File.ReadAllText

    [TestMethod]
    public void Foo()
    {
        using (ShimsContext.Create())
        {
            ShimFile.ReadAllTextString = path => "test 123";
            var reverser = new TextReverser();
            const string expected = "321 tset";
            //Act
            var actual = reverser.ReverseSomeTextFromAFile(@"C:\fakefile.txt");
            //Assert
            Assert.AreEqual(expected, actual);
        }
    }

该测试方法正在做的是暂时(在 的范围内)用我提供的 lambdaShimsContext替换实现。File.ReadAllText在这种情况下,任何时候ReadAllText调用它都会返回字符串“test 123”。

它比常规 DI 慢,但如果您完全依赖于单例的特定实现,它可能正是您所需要的。在此处阅读更多相关信息。

于 2012-08-18T16:57:03.157 回答
3

安德斯所说的。

几个流行的模拟框架是MoqRhinoMocks

并且您将更改您的代码,以便将记录器依赖项注入到您的类中:

public class ClassWithMethodsIWantToUnitTest 
{
      public ClassWithMethodsIWantToUnitTest(ILoggerService logger)
      {}

      public void myFcn(object someArg)
      {
         ...
          logger.LogMessage("myMessage");
         ...
      }
}

或类似的东西。DI 框架可以在需要时将记录器自动注入到类中。本质上是一个 DI 框架自动调用

new ClassWithMethodsIWantToUnitTest(LoggerService.Instance);
于 2012-08-18T16:59:49.067 回答