【问题标题】:Avoiding thread.sleep in code while unit testing with Moq使用 Moq 进行单元测试时避免代码中的 thread.sleep
【发布时间】:2019-03-13 09:27:41
【问题描述】:

我的方法有多个 thread.sleep,有时会持续 20 秒。这是业务需求。我正在尝试通过模拟和跳过这些睡眠来对这些方法进行单元测试,以便测试可以更快地运行并且实际上不会等待 20 秒。使用起订量框架。 感谢您对如何实现这一点的任何想法。

【问题讨论】:

  • 对于不是为可测试性而设计的代码,摩擦最小的方法是将睡眠调用分解为可以模拟的虚拟方法。
  • 如果操作的持续时间要求为 20 秒,那么最有价值的测试将测试哪些运行实际实现。如果您想测试在睡眠之间调用的东西,请将这些操作提取到可以单独测试的方法或类中

标签: c# unit-testing moq


【解决方案1】:

可能没有办法模拟 Thread.Sleep,因为它是一个静态方法,不能使用基于 DynamicProxy 的模拟框架(如 moq)来模拟。

一种选择是使用基于 Profiler API 的工具,例如 Microsoft Fakes(仅在 VS Enterprise 中)或 Typemoq 专业版。

更好的选择是不要直接在您的业务逻辑中调用Thread.Sleep。你可以做的是引入这样的接口

public interface ISleepService
{
    void Sleep(int ms);
}

然后创建一个您在代码中使用的默认实现:

public class SleepService: ISleepService
{
    public void Sleep(int ms)
    {
       Thread.Sleep(ms);
    }
}

将 ISleepService 的依赖项添加到您的业务逻辑中

public class MyBusinessLogic()
{
    private ISleepService _sleepService;
    public MyBusinessLogic(ISleepService sleepService)
    {
        _sleepService = sleepSerivce;
    }

    public void MyBusinessMethod()
    {
        // your code
        _sleeService.Sleep(20000);
        // more code
    }
}

然后,您可以轻松地在单元测试中模拟 ISleepService 并在生产代码中传递真正的实现

【讨论】:

    【解决方案2】:

    您实际上可以为 Thread.sleep 方法引入接口,并且您可以在编写 UT 时进行模拟

     public interface IThreadSleep
    {
        void Sleep(int milliSec);
    
    }
    

    你可以有实现,像这样

     public class ThreadSleep : IThreadSleep
    {
        public void Sleep(int milliSec)
        {
            Thread.Sleep(milliSec);
        }
    }
    

    在你的业务类中,只需注入这个接口,你就可以模拟 Thread.sleep

     public class Class1
    {
        IThreadSleep _threadSleep;
        public Class1(IThreadSleep threadSleep)
        {
            _threadSleep = threadSleep;
    
        }
    
        public void SomeMethod()
        {
            // 
            _threadSleep.Sleep(100);
        }
    }
    

    希望这会有所帮助。

    【讨论】:

      【解决方案3】:

      不知道您拥有的实际代码,但至少有一些想法。您可以将 Thread.Sleep 包装到 interface 中,然后将其注入您的业务处理程序\控制器。在实际实现中使用Thread.Sleep 实际等待,但在测试中模拟interface 以避免Thread.Sleep。例如:

      public interface IMySleepContext
      {
          void Sleep(int milliseconds);
      }
      
      public class MySleepContext : IMySleepContext
      {
          public void Sleep(int milliseconds)
          {
              Thread.Sleep(milliseconds);
          }
      }
      
      public class MyController
      {
          private readonly IMySleepContext _mySleepContext;
      
          public MyController(IMySleepContext mySleepContext)
          {
              _mySleepContext = mySleepContext;
          }
      
          public void MyMethod()
          {
              //do something
              _mySleepContext.Sleep(20000);
              //do somethign
          }
      }
      

      测试:

      //Arrange
      MyController mc = new MyController(Mock.Of<IMySleepContext>());
      
      //Act
      mc.MyMethod();
      
      //Assert
      //do assert
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-12-24
        • 2018-06-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-03-29
        相关资源
        最近更新 更多