Asp.net core 如何使用xUnit为使用实体框架核心和简单注入器构建的Asp.NetCore WebAPI构建测试?
我使用实体框架核心和简单注入器创建了一个ASP.NET核心Web API 我希望使用xUnit进行单元测试来测试我的控制器 我不知道从哪里开始。我相信我必须在单元测试中模拟容器对象 以下是初始化容器的启动代码:Asp.net core 如何使用xUnit为使用实体框架核心和简单注入器构建的Asp.NetCore WebAPI构建测试?,asp.net-core,dependency-injection,entity-framework-core,xunit,simple-injector,Asp.net Core,Dependency Injection,Entity Framework Core,Xunit,Simple Injector,我使用实体框架核心和简单注入器创建了一个ASP.NET核心Web API 我希望使用xUnit进行单元测试来测试我的控制器 我不知道从哪里开始。我相信我必须在单元测试中模拟容器对象 以下是初始化容器的启动代码: public class Startup { private Container container; public IConfiguration Configuration { get; } private IConfigurationRoot configur
public class Startup
{
private Container container;
public IConfiguration Configuration { get; }
private IConfigurationRoot configurationRoot;
public Startup(IConfiguration configuration)
{
Configuration = configuration;
// Build configuration info
configurationRoot = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.Build();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
InitializeContainer();
services.AddSimpleInjector(container, options =>
{
options.AddAspNetCore()
.AddControllerActivation();
options.AddLogging();
});
}
private void InitializeContainer()
{
container = new SimpleInjector.Container();
container.Options.ResolveUnregisteredConcreteTypes = false;
container.ConfigureServices();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseSimpleInjector(container);
AppSettingsHelper.AppConfig = configurationRoot;
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
以下是“我的服务”安装程序的代码:
public static class ServicesInstaller
{
public static void ConfigureServices(this Container container)
{
container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
//Assembly.Load will not re-load already loaded Assemblies
container.Register<IFooContext, FooContext>(Lifestyle.Scoped);
container.Register<FooContext>(Lifestyle.Scoped);
}
}
公共静态类服务安装程序
{
公共静态void配置服务(此容器)
{
container.Options.DefaultScopedLifestyle=新的AsyncScopedLifestyle();
//程序集。加载将不会重新加载已加载的程序集
容器。寄存器(生活方式。范围);
容器。寄存器(生活方式。范围);
}
}
以下是一个示例控制器:
[Route("[controller]")]
[ApiController]
public class SomeController : ControllerBase
{
private readonly ILogger<SomeController> _logger;
private readonly Container _container;
public SomeController(ILogger<SomeController> p_Logger, Container p_Container)
{
_logger = p_Logger;
_container = p_Container;
}
[HttpGet]
[Route("{p_SomeId}")]
public Some GetOwnerByOwnerId(Guid p_SomeId)
{
Some some;
using (Scope scope = AsyncScopedLifestyle.BeginScope(_container))
{
var dbContext = _container.GetInstance<FooContext>();
some = dbContext.Somes.Where(x => x.SomeId == p_SomeId).FirstOrDefault();
}
return some;
}
}
[路由(“[控制器]”)]
[ApiController]
公共类控制器:ControllerBase
{
专用只读ILogger\u记录器;
私有只读容器_容器;
公共控制器(ILogger p_记录器、容器p_容器)
{
_记录器=p_记录器;
_容器=p_容器;
}
[HttpGet]
[路线(“{p_SomeId}”)]
公共某些GetOwnerByOwnerId(Guid p_SomeId)
{
有的有的,;
使用(Scope Scope=AsyncScopedLifestyle.BeginScope(_容器))
{
var dbContext=_container.GetInstance();
some=dbContext.Somes.Where(x=>x.SomeId==p_SomeId).FirstOrDefault();
}
还一些;
}
}
我对使用SimpleInjector比较陌生
如何模拟用于测试的容器?所提供示例中的控制器不应耦合到特定于容器的任何对象 显式地将必要的依赖项注入控制器
[Route("[controller]")]
[ApiController]
public class SomeController : ControllerBase {
private readonly ILogger<SomeController> _logger;
private readonly IFooContext dbContext;
public SomeController(ILogger<SomeController> p_Logger, IFooContext dbContext) {
_logger = p_Logger;
this.dbContext = dbContext;
}
[HttpGet]
[Route("{p_SomeId}")]
public Some GetOwnerByOwnerId(Guid p_SomeId) {
Some some = dbContext.Somes.Where(x => x.SomeId == p_SomeId).FirstOrDefault();
return some;
}
}
[路由(“[控制器]”)]
[ApiController]
公共类控制器:ControllerBase{
专用只读ILogger\u记录器;
私有只读IFooContext-dbContext;
公共SomeController(ILogger p_记录器,IFooContext dbContext){
_记录器=p_记录器;
this.dbContext=dbContext;
}
[HttpGet]
[路线(“{p_SomeId}”)]
公共某些GetOwnerByOwnerId(Guid p_SomeId){
Some Some=dbContext.Somes.Where(x=>x.SomeId==p_SomeId).FirstOrDefault();
还一些;
}
}
现在不需要模拟容器,这将被视为实现细节代码气味
模拟依赖项抽象,并在执行单元测试时验证预期行为
控制器还应尽可能精简,因为大多数其他横切关注点(如确保注入的上下文的作用域)在启动时由框架通过配置的容器进行处理