C# 使用ASP.NET Core 2.0集成测试HttpClient如何模拟DateTime。现在使用依赖项注入

C# 使用ASP.NET Core 2.0集成测试HttpClient如何模拟DateTime。现在使用依赖项注入,c#,unit-testing,dependency-injection,mocking,asp.net-core-2.0,C#,Unit Testing,Dependency Injection,Mocking,Asp.net Core 2.0,在.NETCore2.0框架中使用依赖注入和httpClient时,我编写了两个单元测试。 我一直在这样测试我的控制器: var result = await __client.PostAsync("api/production-line/validate-assignment-deadline", null); var controller = new ProductionLineController(mockProductionLineProvider); var mockin

在.NETCore2.0框架中使用依赖注入和httpClient时,我编写了两个单元测试。 我一直在这样测试我的控制器:

var result = await  __client.PostAsync("api/production-line/validate-assignment-deadline", null);
var controller = new ProductionLineController(mockProductionLineProvider);
    var mockingDate = new DateTime(date.Year, date.Month, date.Day, 12, 00, 00);
    __constantsMock.Setup(x => x.GetCurrentDateTime()).Returns(mockingDate);
        services.Replace(new ServiceDescriptor(typeof(IConstants), ConstantsMock.Object));
var result = await  __client.PostAsync("api/production-line/validate-assignment-deadline", null);
但现在我想模拟一个物体,在互联网上搜索了一下后,我能找到的就是这样做:

var result = await  __client.PostAsync("api/production-line/validate-assignment-deadline", null);
var controller = new ProductionLineController(mockProductionLineProvider);
    var mockingDate = new DateTime(date.Year, date.Month, date.Day, 12, 00, 00);
    __constantsMock.Setup(x => x.GetCurrentDateTime()).Returns(mockingDate);
        services.Replace(new ServiceDescriptor(typeof(IConstants), ConstantsMock.Object));
var result = await  __client.PostAsync("api/production-line/validate-assignment-deadline", null);
这不是测试路由,最重要的是我必须创建很多对象。所以我不想这样嘲笑我的对象。 我希望能够用一个模拟对象替换服务,因为我还没有找到将IServiceCollection放入unittest方法的方法

我希望能够做到以下几点:

var result = await  __client.PostAsync("api/production-line/validate-assignment-deadline", null);
var controller = new ProductionLineController(mockProductionLineProvider);
    var mockingDate = new DateTime(date.Year, date.Month, date.Day, 12, 00, 00);
    __constantsMock.Setup(x => x.GetCurrentDateTime()).Returns(mockingDate);
        services.Replace(new ServiceDescriptor(typeof(IConstants), ConstantsMock.Object));
var result = await  __client.PostAsync("api/production-line/validate-assignment-deadline", null);
我希望你能帮助我想出一个解决方案,不需要我创建每一个我正常注入的对象

先谢谢你

编辑:
我确实在做集成测试,我想测试一切,但我需要能够配置来自DateTime的结果。现在,我用一个函数创建了constants类来返回DateTime。现在,我试图模拟/存根该类/函数。这样我就可以测试可能发生的多个场景。

您正在查看模拟的标准方式;您为所有依赖项创建存根(您需要能够控制所有依赖项!)并创建控制器。能够模仿DI框架并不能真正为您带来任何好处;在构建类时,仍然需要向类提供所有依赖项

使用模拟库,如NSubstitute,使其更容易;如果您觉得您有太多的依赖项,那么我怀疑您需要重构您的设计(可能控制器做得太多)


请注意,使用实际HTTP请求进行测试更像是一种集成测试;您正在测试整个应用程序,而不是一个类。在这种情况下,您可以为您的程序设置不同的环境,并使用您需要的任何额外模拟/测试数据设置注入器。

您正在查看模拟的标准方式;您为所有依赖项创建存根(您需要能够控制所有依赖项!)并创建控制器。能够模仿DI框架并不能真正为您带来任何好处;在构建类时,仍然需要向类提供所有依赖项

使用模拟库,如NSubstitute,使其更容易;如果您觉得您有太多的依赖项,那么我怀疑您需要重构您的设计(可能控制器做得太多)


请注意,使用实际HTTP请求进行测试更像是一种集成测试;您正在测试整个应用程序,而不是一个类。在这种情况下,您可以为您的程序设置不同的环境,并使用您需要的任何额外模拟/测试数据来设置注入器。

一旦您开始执行诸如发出操作请求之类的操作,您就完全超出了单元测试领域。你在这里做的是集成测试

只要您正在进行集成测试,就可以使用
TestServer
,这实际上会为您提供一个更准确的集成测试平台。手动设置所有依赖项并不能确保应用程序真正按其应该的方式运行。完整的文档是,但基本上,您只需执行以下操作:

_server = new TestServer(new WebHostBuilder()
    .UseStartup<Startup>());
_client = _server.CreateClient();
\u server=newtestserver(new WebHostBuilder()
.UseStartup());
_client=_server.CreateClient();

\u server.CreateClient()
的返回实际上是
HttpClient
的一个实例,因此您的实际测试代码实际上不需要更改。然而,现在您已经拥有了所有服务和配置的完整模型。

一旦您开始执行诸如向操作发出请求之类的操作,您就完全脱离了单元测试领域。你在这里做的是集成测试

只要您正在进行集成测试,就可以使用
TestServer
,这实际上会为您提供一个更准确的集成测试平台。手动设置所有依赖项并不能确保应用程序真正按其应该的方式运行。完整的文档是,但基本上,您只需执行以下操作:

_server = new TestServer(new WebHostBuilder()
    .UseStartup<Startup>());
_client = _server.CreateClient();
\u server=newtestserver(new WebHostBuilder()
.UseStartup());
_client=_server.CreateClient();

\u server.CreateClient()
的返回实际上是
HttpClient
的一个实例,因此您的实际测试代码实际上不需要更改。但是,现在您已经获得了所有服务和配置的完整模型。

我的问题的解决方案如下:

  • 创建一个从启动类继承的额外启动类
  • 为该类提供以下代码:

    public class UnitTestStartup : Startup
    {
        public static IServiceProvider ServiceProvider;
        public static IServiceCollection Services;
        public static Mock<IConstants> ConstantsMock; 
    
        public void ConfigureTestingServices(IServiceCollection services)
        {
    
                ServiceProvider = base.ConfigureServices(services);
                Services = services;
                ConstantsMock = new Mock<IConstants>();
    
                services.Replace(new ServiceDescriptor(typeof(IConstants), ConstantsMock.Object));
        }
    }
    
    public类UnitTestStartup:Startup
    {
    公共静态IServiceProvider服务提供商;
    公共收集服务;
    公共静态Mock-ConstantsMock;
    public void ConfigureTestingServices(IServiceCollection服务)
    {
    ServiceProvider=base.ConfigureServices(服务);
    服务=服务;
    ConstantsMock=新Mock();
    Replace(新的ServiceDescriptor(typeof(IConstants),ConstantsMock.Object));
    }
    }
    
  • 使ConstantsMock(您想要模拟的服务)在基类中可用 像这样:

    protected Mock<IConstants> __constantsMock;
    __constantsMock = UnitTestStartup.ConstantsMock;
    
    protectedmock\uuu constantsMock;
    __constantsMock=UnitTestStartup.constantsMock;
    
  • 让每个单元测试类都从基类继承

  • 用一个新对象覆盖
    \uu constantsMock
    ,就完成了


    • 我的问题的解决方案如下:

      • 创建一个从启动类继承的额外启动类
      • 为该类提供以下代码:

        public class UnitTestStartup : Startup
        {
            public static IServiceProvider ServiceProvider;
            public static IServiceCollection Services;
            public static Mock<IConstants> ConstantsMock; 
        
            public void ConfigureTestingServices(IServiceCollection services)
            {
        
                    ServiceProvider = base.ConfigureServices(services);
                    Services = services;
                    ConstantsMock = new Mock<IConstants>();
        
                    services.Replace(new ServiceDescriptor(typeof(IConstants), ConstantsMock.Object));
            }
        }
        
        公共类UnitTestStar