c# - 包装静态类/方法以便对其进行单元测试?

标签 c# .net unit-testing nunit moq

我有一个用于日志记录的静态类:

public static class myLogger
{
    public static ErrorLogging(string input)
    {
        //dostuff
    }
}

我的使用方式是:

public class myClassthatDoesStuff
{
    ...
    myLogger.ErrorLogging("some error ocurred");
    ...
}

如何对 myLogger 类进行最小化,以便能够对其进行单元测试并确保执行 ErrorLogging 方法? 是否可以在构造函数中不设置任何参数(构造函数注入(inject))的情况下执行此操作? myClassthatDoesStuff 要求构造函数中没有参数。

最佳答案

This blog post描述了完全相同的场景 - 您有一个旧的静态日志记录方法并希望在可测试代码中使用它。

  • 将静态类包装在非静态类中 - 不仅用于测试,还用于一般用途。

  • 将新的非静态类的方法提取到接口(interface)中。

  • 无论您在何处依赖静态类,都应改为依赖接口(interface)。例如,如果类 DoesSomething 需要静态类中的函数,请执行以下操作:

      public interface ILogger
      {
          void ErrorLogging(string input);
      }
    
      public class MyClassthatDoesStuff
      {
          private readonly ILogger _logger;
    
          public MyClassthatDoesStuff(ILogger logger)
          {
              _logger = logger;
          }
      }
    

这有两个好处:

  1. 您可以对您的旧静态类进行单元测试(假设它没有状态并且不依赖于任何具有任何状态的东西)(尽管如果是这种情况我想您无论如何都可以对它进行单元测试。)

  2. 您可以对将使用该静态类的代码进行单元测试(通过删除对该静态类的直接依赖。)您可以将 ILogger 替换为模拟类,例如添加您的模拟类错误消息列表。

    class StringLogger : List<string>, ILogger
    {
        public void ErrorLogging(string input)
        {
           Add(input);
        }
    }
    
    var testSubject = new MyClassthatDoesStuff(new StringLogger());
    

一个更简单的选项不需要创建接口(interface)和适配器类。您可以创建一个 delegate这就像一个方法的接口(interface)。

在记录器的情况下,它将是

delegate void Logging ErrorLoggingMethod(string input);

使用它看起来类似于使用界面:

    public class MyClassthatDoesStuff
    {
        private readonly ErrorLoggingMethod _logger;

        public MyClassthatDoesStuff(ILogger logger)
        {
            _logger = logger;
        }

        public void DoSomethingThatLogs()
        {
            // _logger is a method
            _logger("Log something");
        }
    }

这更容易模拟和测试

string loggedMessage = null;
ErrorLoggingMethod fakeLogger = (input) => loggedMessage = input;

您可以将假记录器注入(inject)到您正在测试的类中。如果该类调用记录器,该方法会将记录的内容分配给变量。然后您可以断言已记录的任何内容,或仅断言已记录任何内容。

如果您的应用使用依赖项注入(inject)/IoC 容器,您可以像注册接口(interface)一样注册委托(delegate)。 Here's an example .

关于c# - 包装静态类/方法以便对其进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35827806/

相关文章:

c# - 将 DataTable(动态列)转换为 List<T>

基于 .NET 的 IRC 服务器

c# - 使用户能够从另一个进程中选择控件/窗口

c++ - assert() 意外触发时如何抑制 Google 测试中的终止?

reactjs - 未定义的“_isMockFunction”

java - 将模型注入(inject)到具有 @Autowired 注释的 bean 中

c# - EF 随机看到错误的属性类型

c# - 什么是 ASP.NET Core 中的服务器垃圾回收?

c# - 为什么最后才调用 GC.KeepAlive,而不是最开始?

c# - 有两个相同的数组是否需要双倍的内存?