C# 具有模拟延迟的集成测试调用

C# 具有模拟延迟的集成测试调用,c#,.net-core,integration-testing,asp.net-core-webapi,xunit,C#,.net Core,Integration Testing,Asp.net Core Webapi,Xunit,我正在测试一个asp.net Core 2.2 WebApi后端,它使用EF Core实现数据持久性 该解决方案使用干净的体系结构和存储库/服务模式实现,使每个组件都可以单独测试 我的集成测试(使用XUnit和EF Core内存数据库)需要测试以下情况: 用户发出一个请求并立即发出另一个相同的请求 用户发出一个请求,15秒后,发出另一个相同的请求 用户发出一个请求,30秒后,发出另一个相同的请求 每个病例各有5个变种。现在,我正在使用一个Thread.Sleep(x)调用来模拟这种延迟。当然,这

我正在测试一个asp.net Core 2.2 WebApi后端,它使用EF Core实现数据持久性

该解决方案使用干净的体系结构和存储库/服务模式实现,使每个组件都可以单独测试

我的集成测试(使用XUnit和EF Core内存数据库)需要测试以下情况:

  • 用户发出一个请求并立即发出另一个相同的请求
  • 用户发出一个请求,15秒后,发出另一个相同的请求
  • 用户发出一个请求,30秒后,发出另一个相同的请求
  • 每个病例各有5个变种。现在,我正在使用一个
    Thread.Sleep(x)
    调用来模拟这种延迟。当然,这意味着我的集成测试需要很长时间才能完成。延迟用于存储库层在每次调用时保存
    DateTime.UtcNow
    值;服务层使用其值来执行一些业务逻辑决策

    我想知道的是,是否有一种方法可以使用测试框架来“模拟”这些延迟,从而消除测试实际等待这一次的需要,并诱使存储库层使用一个
    DateTime.UtcNow
    值,该值以
    x
    递增


    谢谢你

    DateTime
    访问抽象到某个接口后面

    public interface IDateTime { 
        DateTime UtcNow { get; }
    
        //...other members as needed. eg: DateTime Now { get; }
    } 
    
    在测试时,可以模拟其行为

    生产实现将简单地包装实际的
    DateTime

    public class DefaultClock : IDateTime {
        public DateTime UtcNow => DateTime.UtcNow;
    
        //...
    }
    
    并在DI容器中注册

    service.AddSingleton<IDateTime, DefaultClock>();
    
    service.AddSingleton();
    
    测试时,可以根据需要模拟抽象

    //Arrange
    DateTime time;
    DatTime.TryParse("2009-05-01 12:00:00", out time);
    
    var mock = new Mock<IDateTime>(); //USING MOQ
    
    mock.SetupSequence(_ => _.UtcNow)
        .Returns(time);                 //first call
        .Returns(time.AddSeconds(15))   //second call
        .Returns(time.AddSeconds(30));  //third call
    
    IDateTime clock = mock.Object;
    
    //...inject clock into subject under test
    
    //排列
    日期时间;
    DatTime.TryParse(“2009-05-01 12:00:00”,超时);
    var mock=new mock()//使用最小起订量
    mock.SetupSequence(=>uCnow)
    .返回(时间)//第一个电话
    .Returns(time.AddSeconds(15))//第二次调用
    .返回(time.AddSeconds(30))//第三次呼叫
    IDateTime时钟=mock.Object;
    //…将时钟注入受测对象
    
    在一些接口
    接口IClock{DateTime UtcNow{get;}}}
    后面抽象
    日期时间
    访问,在测试时可以模拟该接口,使其按需要运行。这取决于时间范围的含义。如果你只是想知道将来某个时候会发生什么,那么@Nkosi是对的:你可以模拟时钟,并将时间设置为未来的时间。然而,在这里,您很可能正在寻找一种并发或类似并发的类型,在这种情况下,您实际上需要实时地将调用隔开。因此,您要么接受更长的测试时间,要么将其移动到不同的(通常是手动的)测试层。例如,它可能由实际的UAT人员运行。在这种情况下,测试时间本身并不是什么大问题。只有当它是您的CI管道的一部分时才有问题。@Nkosi,这是个好主意!如果您希望我将其设置为已接受,请将其作为答案发布。@ChrisPratt,我们正在查看并发情况/行为,但由于所有内容的结构,测试并发调用/幂等性问题在“案例1”中处理,这不会增加测试时间。其余的测试处理幂等性问题,但有些不同,这些测试将与建议的日期时抽象解决方案兼容。是的,问题出现在我们的CI/CD管道上。我有一个政策,任何PR必须首先通过一个测试流水线,这真的减慢了事情。还考虑了NotoTiMe库,它基本上是为了这个而在CLR类型中有很多其他缺陷。但是现在我更愿意添加一个我完全控制的自定义接口,而不是向解决方案添加另一个依赖项。根据上面的答案,依赖NodaTime而不是实现自定义界面是否有任何“隐藏”优势?取决于应用程序的需要。它比CLR类型更能处理i18n需求。你可以做实际的日历计算,用实际的时区来代替偏移量,在偏移量中,像DST这样的东西会让你很难受。