C#Net Core 3.1单元测试中自动生成标识列
我的基础课C#Net Core 3.1单元测试中自动生成标识列,c#,.net-core,integration-testing,xunit.net,in-memory-database,C#,.net Core,Integration Testing,Xunit.net,In Memory Database,我的基础课 public class Book { public int Id { get; set;} public string Title { get; set;} } public class Author { public Author () { BookList = new HashSet<Book> (); for (int i = 0; i<
public class Book {
public int Id { get; set;}
public string Title { get; set;}
}
public class Author {
public Author () {
BookList = new HashSet<Book> ();
for (int i = 0; i< 10; i++) {
var book = new Book() {
Title = "Funny book" + i;
}
BookList.Add(book);
}
}
public int Id { get; set;}
public string Name { get; set;}
public ICollection<Book> BookList { get; set; }
}
在单元测试方法中,如果我没有为book对象指定Id,它将抛出一个错误,表示Id=1000的对象已经被另一个实体跟踪
我的理由如下:
(1) 当我创建Author测试数据时,它为每个作者创建了许多书籍。由于字段是SQL表的标识列,因此创建这些书籍时未指定Id
(2) 然后,我用指定的Id创建了图书测试数据。已成功创建测试数据
(3) 在单元测试期间,系统似乎对获取下一个可用Id感到困惑
有没有一种方法可以在不指定Id的情况下解决此问题
单元测试在netcore 2.1中运行良好。单元测试转换为net core 3.1后,问题就出现了。如果您将Book类的定义更改为类似以下内容:
public class Book {
public string Id { get; set;}
public string Title { get; set;}
}
您可以通过使用以下命令动态生成新guid来添加其他书籍:
Guid g = Guid.NewGuid();
然后,当您创建新书时,只需调用g.ToString()来获取基础值并将其分配给Id属性。当然,您还必须更改后端数据库表的结构以支持此功能。想想这是如何工作的。。。。您正在告诉您的系统创建一本id为1000的书。运行方法后,数据库中现在有一本id为1000的书。然后再次运行该方法,结果失败,因为显然,id为1000的书籍仍在数据库中 接下来,您模拟您的数据库层并创建一个ID为1000的实体,但您永远无法摆脱它。下次运行方法时,可能会遇到实体跟踪问题 这个你称之为测试的东西,实际上不是一个测试,因为没有断言,你没有检查任何东西,因此它不是一个测试 这一切都非常复杂,必然会产生拉扯头发的问题。您试图做的事情告诉我,您真正想要的是集成测试,而不是单元测试 如果你想进行单元测试,我会说把EF从测试中去掉,把重点放在真正的功能上,比如业务规则等等 进行集成测试并不是一件坏事,但如果您在调用结束时创建了真实的数据,您还应该清理它 实际的集成测试如下所示:
这是一些数据,我调用这个方法,我应该得到这个结果。这将适用于单元测试。在我的测试中创建一本书时,我正在使用一个实用程序函数来分配Id。我试图在不指定Id的情况下找到解决方案。@user3097695通过修改该函数将Id指定为Guid.NewGuid()方法调用的结果,您不需要手动指定Id,因为每次调用该方法时系统都会生成新的Guid。由于数据库已在生产中一段时间,我们无法更改Id的定义。实际的API调用没有问题,但它只影响单元测试。我需要找到这些行为背后的深层原因。好吧,也许你可以使用一个helper函数从数据库中选择ID的最大值,并简单地为新ID增加1?我已经在为单元测试做这个了。我认为NetCore 3.1中可能有一个bug。我认为我不需要添加Id。系统应该自动添加下一个可用Id。您有一个有效的点。我想我想问的是为什么NetCore 2.1和NetCore 3.1之间存在不同的行为。
[Fact]
public async Task CreateBookTest()
{
var context = BookContextMock.ConfigureBookContext(new ServiceCollection());
BookRepository repo = new BookRepository(context);
Book book = new BookSensor()
{
Title = "New Book 1",
};
var newBook = await repo.CreateBook(book);
}
public class Book {
public string Id { get; set;}
public string Title { get; set;}
}
Guid g = Guid.NewGuid();