C# 如何在DbContext-主键中并行运行Xunit而不发生冲突?
我正在使用内存数据库创建Xunit测试。如果单独运行,测试将正确执行。但是,如果并行运行,它们会由于dbcontext中的主键问题而发生冲突 解决这个问题的最佳选择是什么C# 如何在DbContext-主键中并行运行Xunit而不发生冲突?,c#,entity-framework,asp.net-core,.net-core,xunit,C#,Entity Framework,Asp.net Core,.net Core,Xunit,我正在使用内存数据库创建Xunit测试。如果单独运行,测试将正确执行。但是,如果并行运行,它们会由于dbcontext中的主键问题而发生冲突 解决这个问题的最佳选择是什么 Xunit是否具有拆卸功能?听说xunit没有 支持这一点 我应该按顺序运行测试吗 应该继续使用不同的密钥ID吗 试图研究xunit文档,刚刚开始学习.net编程 错误: "System.ArgumentException : An item with the same key has already been added.
"System.ArgumentException : An item with the same key has already been added. Key: 2"
代码:
"System.ArgumentException : An item with the same key has already been added. Key: 2"
2是主键,使用两次
public class ProductAppServiceTest
{
public TestContext context;
public IMapper mapper;
public ProductAppServiceTest()
{
var options = new DbContextOptionsBuilder<TestContext>()
.UseInMemoryDatabase(databaseName: "TestDatabase")
.Options;
context = new TestContext(options);
ApplicationServicesMappingProfile applicationServicesMappingProfile = new ApplicationServicesMappingProfile();
var config = new MapperConfiguration(cfg =>
{
cfg.AddProfile(applicationServicesMappingProfile);
});
mapper = config.CreateMapper();
}
[Fact]
public async Task Get_ProductById_Are_Equal()
{
context.Product.Add(new Product { ProductId = 2, ProductCode = "123", ProductName = "ABC" });
context.SaveChanges();
var ProductRepository = new ProductRepository(context);
var ProductAppService = new ProductAppService(ProductRepository, mapper);
var ProductDto = await ProductAppService.GetProductById(2);
Assert.Equal("123", ProductDto.ProductCode);
}
[Fact]
public async Task Get_ProductPrice_Are_Equal()
{
context.Product.Add(new Product { ProductId = 2, ProductCode = "123", ProductName = "ABC" });
context.SaveChanges();
var ProductRepository = new ProductRepository(context);
var ProductAppService = new ProductAppService(ProductRepository, mapper);
var ProductDto = await ProductAppService.GetProductById(2);
//Goes into Enum table to validate price is 5
Assert.Equal("5", ProductDto.Price);
}
公共类ProductAppServiceTest
{
公共测试语境;
公共图像映射器;
公共产品AppServiceTest()
{
var options=new DbContextOptionsBuilder()
.UseInMemoryDatabase(数据库名称:“TestDatabase”)
.选择;
上下文=新的TestContext(选项);
ApplicationServicesMappingProfile ApplicationServicesMappingProfile=新的ApplicationServicesMappingProfile();
var config=new-MapperConfiguration(cfg=>
{
AddProfile(applicationServicesMappingProfile);
});
mapper=config.CreateMapper();
}
[事实]
公共异步任务Get_ProductById_Are_Equal()
{
context.Product.Add(新产品{ProductId=2,ProductCode=“123”,ProductName=“ABC”});
SaveChanges();
var ProductRepository=新的ProductRepository(上下文);
var ProductAppService=新的ProductAppService(ProductRepository,mapper);
var ProductDto=await ProductAppService.GetProductById(2);
Assert.Equal(“123”,ProductDto.ProductCode);
}
[事实]
公共异步任务Get_ProductPrice_Are_Equal()
{
context.Product.Add(新产品{ProductId=2,ProductCode=“123”,ProductName=“ABC”});
SaveChanges();
var ProductRepository=新的ProductRepository(上下文);
var ProductAppService=新的ProductAppService(ProductRepository,mapper);
var ProductDto=await ProductAppService.GetProductById(2);
//进入枚举表以验证价格是否为5
断言相等(“5”,产品与价格之比);
}
这里的问题是,每个测试都使用相同的内存数据库。虽然可以为每个测试拆卸和创建数据库,但通常更容易为每个测试使用唯一的数据库
注意:每个测试使用相同数据库的原因是因为您使用的是静态数据库名称
XUnit在每次测试之前调用测试类构造函数,因此您可以使用guid
作为数据库名称,为每个测试创建一个唯一的内存中数据库
var options=new DbContextOptionsBuilder()
.UseInMemoryDatabase(数据库名称:Guid.NewGuid().ToString())
.选择;
上下文=新的TestContext(选项);
示例测试将无法正确并行执行,因为它们是同一集合的成员
默认情况下,每个测试类都是唯一的测试集合
同一个测试类不会彼此并行运行。
-
源代码中的TestContext是什么,它是某种类型的单例吗?如果是这样,当并行运行时,因为两个测试都在同一个集合中,它将在xUnit启动的类的两个实例之间共享(即使在同一个集合中创建了每个类的新副本)
如果您确实需要在集合或程序集中共享,我建议您使用内置的TestFixture功能,或者实现一个程序集夹具
xUnit中的安装和拆卸是通过构造函数和IDisposable实现的,或者通过在测试类上实现IAsyncLifetime实现的。注意:并行运行时,DisposeSync将在启动每个dispose之前等待测试运行
public class UnitTest : IDisposable, IAsyncLifetime
{
public UnitTest()
{
//First
}
public Task InitializeAsync()
{
//Second
}
[Fact]
public async Task Test1()
{
//Third
}
public Task DisposeAsync()
{
//Forth
}
public void Dispose()
{
//Fifth
}
}
为了避免多处理任务更改其他任务使用的数据时出现问题,我的简单答案是开发一个数据结构,其中每个任务都传递一个索引,告诉它们要使用结构的哪一部分,当并行作业全部完成时,数据就可以重新组合到原始的主数据结构中您通常使用的。为每个测试拆卸或创建新的上下文。您是否尝试过设置
数据库名称:$“{Guid.NewGuid()}”
,而不是设置数据库名称:“TestDatabase”
,以便每个并行运行将使用不同的数据库进行测试?使用相同的内存中数据库可能是它们相互重叠的原因。