C# 在集成测试ASP.NET Core Web API和EF Core时重新配置依赖项
我正在学习本教程C# 在集成测试ASP.NET Core Web API和EF Core时重新配置依赖项,c#,asp.net-core,integration-testing,entity-framework-core,xunit2,C#,Asp.net Core,Integration Testing,Entity Framework Core,Xunit2,我正在学习本教程 我的代码如下所示 集成测试类 public class ControllerRequestsShould : IDisposable { private readonly TestServer _server; private readonly HttpClient _client; private readonly YourContext _context; public ControllerRequestsShould() {
我的代码如下所示 集成测试类
public class ControllerRequestsShould : IDisposable
{
private readonly TestServer _server;
private readonly HttpClient _client;
private readonly YourContext _context;
public ControllerRequestsShould()
{
// Arrange
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkSqlServer()
.BuildServiceProvider();
var builder = new DbContextOptionsBuilder<YourContext>();
builder.UseSqlServer($"Server=(localdb)\\mssqllocaldb;Database=your_db_{Guid.NewGuid()};Trusted_Connection=True;MultipleActiveResultSets=true")
.UseInternalServiceProvider(serviceProvider);
_context = new YourContext(builder.Options);
_context.Database.Migrate();
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.UseEnvironment(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")));
_client = _server.CreateClient();
}
[Fact]
public async Task ReturnListOfObjectDtos()
{
// Arrange database data
_context.ObjectDbSet.Add(new ObjectEntity{ Id = 1, Code = "PTF0001", Name = "Portfolio One" });
_context.ObjectDbSet.Add(new ObjectEntity{ Id = 2, Code = "PTF0002", Name = "Portfolio Two" });
// Act
var response = await _client.GetAsync("/api/route");
response.EnsureSuccessStatusCode();
// Assert
var result = Assert.IsType<OkResult>(response);
}
public void Dispose()
{
_context.Dispose();
}
public void ConfigureServices(IServiceCollection services)
{
// Add framework services
services.AddMvc(setupAction =>
{
setupAction.ReturnHttpNotAcceptable = true;
setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter());
});
// Db context configuration
var connectionString = Configuration["ConnectionStrings:YourConnectionString"];
services.AddDbContext<YourContext>(options => options.UseSqlServer(connectionString));
// Register services for dependency injection
services.AddScoped<IYourRepository, YourRepository>();
}
我在startup类中发现连接字符串为空的错误。我认为我对这个问题的理解是,当我的控制器被客户端击中时,它会注入我的数据存储库,而数据存储库又会注入数据库上下文
我想我需要将服务配置为newwebhostbuilder
部分的一部分,以便它使用在测试中创建的上下文。但我不知道该怎么做
在Startup.cs中配置服务方法
public class ControllerRequestsShould : IDisposable
{
private readonly TestServer _server;
private readonly HttpClient _client;
private readonly YourContext _context;
public ControllerRequestsShould()
{
// Arrange
var serviceProvider = new ServiceCollection()
.AddEntityFrameworkSqlServer()
.BuildServiceProvider();
var builder = new DbContextOptionsBuilder<YourContext>();
builder.UseSqlServer($"Server=(localdb)\\mssqllocaldb;Database=your_db_{Guid.NewGuid()};Trusted_Connection=True;MultipleActiveResultSets=true")
.UseInternalServiceProvider(serviceProvider);
_context = new YourContext(builder.Options);
_context.Database.Migrate();
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.UseEnvironment(Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT")));
_client = _server.CreateClient();
}
[Fact]
public async Task ReturnListOfObjectDtos()
{
// Arrange database data
_context.ObjectDbSet.Add(new ObjectEntity{ Id = 1, Code = "PTF0001", Name = "Portfolio One" });
_context.ObjectDbSet.Add(new ObjectEntity{ Id = 2, Code = "PTF0002", Name = "Portfolio Two" });
// Act
var response = await _client.GetAsync("/api/route");
response.EnsureSuccessStatusCode();
// Assert
var result = Assert.IsType<OkResult>(response);
}
public void Dispose()
{
_context.Dispose();
}
public void ConfigureServices(IServiceCollection services)
{
// Add framework services
services.AddMvc(setupAction =>
{
setupAction.ReturnHttpNotAcceptable = true;
setupAction.OutputFormatters.Add(new XmlDataContractSerializerOutputFormatter());
setupAction.InputFormatters.Add(new XmlDataContractSerializerInputFormatter());
});
// Db context configuration
var connectionString = Configuration["ConnectionStrings:YourConnectionString"];
services.AddDbContext<YourContext>(options => options.UseSqlServer(connectionString));
// Register services for dependency injection
services.AddScoped<IYourRepository, YourRepository>();
}
public void配置服务(IServiceCollection服务)
{
//添加框架服务
services.AddMvc(setupAction=>
{
setupAction.ReturnHttpNotAcceptable=true;
setupAction.OutputFormatters.Add(新的XmlDataContractSerializerOutputFormatter());
setupAction.InputFormatters.Add(新的XmlDataContractSerializerInputFormatter());
});
//数据库上下文配置
var connectionString=Configuration[“ConnectionStrings:YourConnectionString”];
services.AddDbContext(options=>options.UseSqlServer(connectionString));
//为依赖注入注册服务
services.addScope();
}
这里有两个选项:
1.使用WebHostBuilder.ConfigureServices
使用WebHostBuilder.ConfigureServices
和WebHostBuilder.UseStartup
覆盖和模拟web应用程序的DI注册:
_server = new TestServer(new WebHostBuilder()
.ConfigureServices(services =>
{
services.AddScoped<IFooService, MockService>();
})
.UseStartup<Startup>()
);
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
//use TryAdd to support mocking IFooService
services.TryAddTransient<IFooService, FooService>();
}
}
或者,可以从头开始创建TestStartup
,以保持测试更干净
并在UseStartup
中指定它以运行测试服务器:
_server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());
\u server=newtestserver(new WebHostBuilder().usestaupt());
这是一个完整的大例子:。@ilya chumakov的答案非常棒。我只想再增加一个选项
3。使用WebHostBuilderExtensions中的ConfigureTestServices方法。
ConfigureTestServices方法在Microsoft.AspNetCore.TestHost 2.1版中提供(2018年5月20日为RC1最终版)。它允许我们用mock覆盖现有的注册
守则:
_server = new TestServer(new WebHostBuilder()
.UseStartup<Startup>()
.ConfigureTestServices(services =>
{
services.AddTransient<IFooService, MockService>();
})
);
\u server=newtestserver(new WebHostBuilder()
.UseStartup()
.ConfigureTestServices(服务=>
{
services.AddTransient();
})
);
它如何覆盖Startup.cs
中的方法“public void ConfigureServices(IServicCollection services)``不是Virtual
?@gauravaroa,只需创建一个基本方法Virtual
。它不会破坏任何东西。除非被推入另一个系统,否则它无法解决问题issue@GauravAroraa,问题是甚么?您只需要在TestStartup
类中执行正确的代码。做这件事的方法并不重要。甚至可以在baseStartup
class中传递变量,这是最好的方法。您还可以删除一些注册,例如services.RemoveAll(typeof(IHostedService))
在我看到这个答案之前,我正在测试中加入依赖项注入.ConfigureServices。这意味着我必须在实际代码中使用.TryAddTransient,而不是AddTransient。我更喜欢这种方式。因为我更新了.net core 3.0,看起来我需要先删除以前的注册:-(最佳选项,保存日期:D