Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# &引用;"剔除";用于单元测试的函数_C#_Unit Testing_Testing - Fatal编程技术网

C# &引用;"剔除";用于单元测试的函数

C# &引用;"剔除";用于单元测试的函数,c#,unit-testing,testing,C#,Unit Testing,Testing,我想使用Visual Studio的C#内置单元测试功能对各种方法进行单元测试。事情进展得相当顺利,但我遇到了一个场景,在这个场景中,我想“剔除”对特定函数调用的依赖 也就是说,我有以下格式的一些方法: public class ClassWithMethodsIWantToUnitTest { public void myFcn(object someArg) { ... LoggerService.Instance.LogMessage("m

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

也就是说,我有以下格式的一些方法:

public class ClassWithMethodsIWantToUnitTest 
{
    public void myFcn(object someArg)
    {
        ...
        LoggerService.Instance.LogMessage("myMessage");
        ...
    }
}
所以基本上,我希望我的单元测试只是验证对“LogMessage”的调用是否已经发生。我不想实际检查日志文件或任何东西。我想知道LoggerService线路是否被击中并执行

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

基于这个问题的格式,在我看来,在我的单元测试中,应该能够以某种方式控制代码。换句话说,我有没有办法制作一个虚假版本的LogMessage,这样我就可以在单元测试中使用它?如果可能的话,我不希望调用“real”LogMessage函数。我只想测试代码是否符合调用函数的路径


这有什么意义吗?这可能吗?

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

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


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

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);
        }
    }
该测试方法正在做的是暂时(在
ShimsContext
的范围内)用我提供的lambda替换
File.ReadAllText
的实现。在这种情况下,无论何时调用
ReadAllText
,它都会返回字符串“test 123”

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

安德斯说了什么

几种流行的模拟框架是和

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

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

      public void myFcn(object someArg)
      {
         ...
          logger.LogMessage("myMessage");
         ...
      }
}
或者类似的东西。DI框架可以在需要时自动将记录器注入类中。本质上,DI框架会自动调用

new ClassWithMethodsIWantToUnitTest(LoggerService.Instance);

+1那真的很酷,以前不知道新的假货。一定要仔细阅读。这很酷,但要注意这会影响性能。在我有限的测试中,一个简单的测试,我希望我能为这个问题选择两个答案。从古典意义上讲,你的回答很有启发性。在接受你的答案和丹尼尔的答案之间是一个艰难的抉择,但是丹尼尔提出的“假货”概念非常有趣。