Asp.net core webapi 在API中,使用一个参数创建多个控制器构造函数 [路由(“api/[控制器]”)] 公共类DigitalDocumentController:控制器 { 私有IDigitalDocumentService数字文档服务; 私有IDatabaseInitializer数据库初始化器; 公共数字文档控制器(IDigitalDocumentService数字文档服务) { this.digitalDocumentService=digitalDocumentService; } 公共数字文档控制器(IDatabaseInitializer数据库Initializer) { this.databaseInitializer=databaseInitializer; }
我希望我的项目中的两个控制器构造函数在xUnit测试中模拟,但我的swagger接口中有一个错误{ “错误”:“在类型'i2ana.Web.Controllers.DigitalDocumentController'中找到了多个接受所有给定参数类型的构造函数。应该只有一个适用的构造函数。” } 有人能帮我怎么做吗 … 我试图做的是测试数据库中名称字段的唯一性 我的测试代码:Asp.net core webapi 在API中,使用一个参数创建多个控制器构造函数 [路由(“api/[控制器]”)] 公共类DigitalDocumentController:控制器 { 私有IDigitalDocumentService数字文档服务; 私有IDatabaseInitializer数据库初始化器; 公共数字文档控制器(IDigitalDocumentService数字文档服务) { this.digitalDocumentService=digitalDocumentService; } 公共数字文档控制器(IDatabaseInitializer数据库Initializer) { this.databaseInitializer=databaseInitializer; },asp.net-core-webapi,Asp.net Core Webapi,我希望我的项目中的两个控制器构造函数在xUnit测试中模拟,但我的swagger接口中有一个错误{ “错误”:“在类型'i2ana.Web.Controllers.DigitalDocumentController'中找到了多个接受所有给定参数类型的构造函数。应该只有一个适用的构造函数。” } 有人能帮我怎么做吗 … 我试图做的是测试数据库中名称字段的唯一性 我的测试代码: [事实] public void AddNotUniqueName_ReturnsNotFoundObjectResult
[事实]
public void AddNotUniqueName_ReturnsNotFoundObjectResult()
{
var digitalDocument=新的digitalDocument
{
Image=新字节[]{0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20},
CreatedOn=DateTime。今天,
Id=6,
Location=“temp”,
Name=“Flower”,
Tages=new List{new Tag{Id=1,Value=“Tag 1”},new Tag{Id=1,Value=“Tag 2”}
};
//安排
var mockRepo=new Mock();
Setup(repo=>repo.SeedAsync()).Returns(Task.FromResult(AddUniqueDigitalDocument(digitalDocument)));
var控制器=新的DigitalDocumentController(mockRepo.Object);
//表演
var结果=controller.Add(数字文档);
//断言
var viewResult=Assert.IsType(结果);
var model=Assert.IsAssignableFrom(viewResult.Value);
Assert.NotEqual(6,模型);
}
“AddUniqueDigitalDocument”返回6仅用于测试新的digitaldocumet是否与我的初始化数据的id不同。使用依赖项注入时,您应该只有一个可以满足所有依赖项的构造函数。否则,DI容器如何知道要使用哪个构造函数?这是您的问题。使用Microsoft.Extensions.dependency注入包,因为这是您注入到的控制器,所以只有一种合理的方法来解决这个问题:不要注册一个或另一个服务,
IDigitalDocumentService
或IDataBabaseInitializer
。如果只注册了一个,服务集合将只使用它已注册的构造函数为……服务
有了一个更具特色的DI容器,您可能可以配置一些东西,以允许它选择合适的构造函数。但是,如何做到这一点完全取决于您最终使用的DI容器,因此在这一点上没有更多的内容可以说。只需了解默认容器(Microsoft.Extensions.DependencyInjection)是有意简化的,因此,如果您需要更复杂的内容,您应该将其放入完整的DI容器中
更新
您应该使用测试主机和内存中数据库进行集成测试。基本方法是:
public MyTests()
{
_server = new TestServer(new WebHostBuilder().UseStartup<TestStartup>());
_context = _server.Host.Services.GetRequiredService<MyContext>();
_client = _server.CreateClient();
}
然后,在ConfigureServices
中,用调用此方法替换数据库设置
最后,在测试项目中,创建一个TestStartup
类并重写ConfigureDatabase
方法:
public class TestStartup : Startup
{
public override void ConfigureDatabase(IServiceCollection services)
{
var databaseName = Guid.NewGuid().ToString();
services.AddDbContext<MyContext>(o =>
o.UseInMemoryDatabase(databaseName));
}
}
无可否认,使用API要容易得多,就像使用web应用程序一样,您总是需要进行一些HTML解析
此外,在实际操作中,您可能希望使用测试夹具,以避免每次测试都必须引导测试服务器。同样,您已经在这里介绍了文档。但是,需要注意的是,一旦切换到使用夹具,您的数据库将在测试之间保持。要隔离测试数据,请确保调用public class MyTests : IClassFixture<WebApplicationFactory<Startup>>
{
private readonly HttpClient _client;
private readonly MyContext _context;
public MyTests(WebApplicationFactory<Startup> factory)
{
factory = factory.WithWebHostBuilder(builder => builder.UseStartup<TestStartup>());
_client = factory.CreateClient();
_context = factory.Server.Host.Services.GetRequiredService<MyContext>();
_context.EnsureDeleted();
}
公共类MyTests:IClassFixture
{
私有只读HttpClient\u客户端;
私有只读MyContext\u上下文;
公共MyTests(WebApplicationFactory工厂)
{
factory=factory.WithWebHostBuilder(builder=>builder.UseStartup());
_client=factory.CreateClient();
_context=factory.Server.Host.Services.GetRequiredService();
_context.EnsureDeleted();
}
不过,我甚至不喜欢测试中有这么多引导代码,所以我通常从fixture类继承:
public class TestServerFixture : IClassFixture<WebApplicationFactory<Startup>>
{
protected readonly HttpClient _client;
protected readonly MyContext _context;
public TestServerFixture(WebApplicationFactory<Startup> factory)
{
factory = factory.WithWebHostBuilder(builder => builder.UseStartup<TestStartup>());
_client = factory.CreateClient();
_context = factory.Server.Host.Services.GetRequiredService<MyContext>();
_context.EnsureDeleted();
}
}
公共类TestServerFixture:IClassFixture
{
受保护的只读HttpClient\u客户端;
受保护的只读MyContext\u上下文;
公共TestServerFixture(WebApplicationFactory工厂)
{
factory=factory.WithWebHostBuilder(builder=>builder.UseStartup());
_client=factory.CreateClient();
_context=factory.Server.Host.Services.GetRequiredService();
_context.EnsureDeleted();
}
}
然后,对于每个测试类:
public class MyTests : TestServerFixture
{
public MyTests(WebApplicationFactory<Startup> factory)
: base(factory)
{
}
公共类MyTests:TestServerFixture
{
公共MyTests(WebApplicationFactory工厂)
:基地(工厂)
{
}
这看起来可能很多,但大部分都是一次性设置。这样,您的测试在许多方面都会更加准确、更加健壮,甚至更容易。使用依赖项注入时,您应该只有一个构造函数可以满足所有依赖项。否则,DI容器如何知道要使用哪个构造函数?这就是y我们的问题就在这里。使用Microsoft.Extensions.DependencyInjection包,并且由于这是您要注入的控制器,因此只有一种合理的方法可以解决此问题:不要注册一个或另一个服务,
IDigitalDocumentService
或<
public class TestServerFixture : IClassFixture<WebApplicationFactory<Startup>>
{
protected readonly HttpClient _client;
protected readonly MyContext _context;
public TestServerFixture(WebApplicationFactory<Startup> factory)
{
factory = factory.WithWebHostBuilder(builder => builder.UseStartup<TestStartup>());
_client = factory.CreateClient();
_context = factory.Server.Host.Services.GetRequiredService<MyContext>();
_context.EnsureDeleted();
}
}
public class MyTests : TestServerFixture
{
public MyTests(WebApplicationFactory<Startup> factory)
: base(factory)
{
}