我正在尝试编写一个基于ASP.Net核心的相当简单的Web服务的单元测试。为了持久化,我使用实体框架核心来访问SQL数据库。
在单元测试中,我显然不希望数据库可以从一个测试渗入另一个测试。经过一番搜索,我发现了这篇文章https://docs.microsoft.com/en-us/ef/core/miscellaneous/testing/in-memory。我的测试代码现在看起来像这样:
[Fact]
public void Test_method()
{
var options = new DbContextOptionsBuilder<ServiceContext>()
.UseInMemoryDatabase(databaseName: "Test_method") // Unique name for each test
.Options;
using (var context = new ServiceContext(options))
{
// Add test data
context.Dataset.Add(new ...);
context.SaveChanges();
}
using (var context = new ServiceContext(options))
{
// Perform tests
var controller = new Controller(new Service(context));
...
}
}
这几乎可行,每个测试用例都以一个空的DB开始。但是testdata元素分配的ID不会重置。因此,如果我有一个将一个元素添加到数据库中的测试,而另一个有两个元素添加了测试,则第一个测试中的测试元素可能会获得ID 1或3,具体取决于这两个测试的执行顺序。
有没有一种方法可以确保ID在单个测试方法中始终以1开头?当ID取决于其他测试是否在当前测试之前进行时,执行基于ID的查找的测试代码确实非常丑陋。
答案 0 :(得分:1)
Entity Framework inmemory database
不会重置其自动增量计数器。
以下是Github问题的声明:
The InMemory provider doesn't the Identity pattern you would get in a relational database. When a column is configured as ValueGeneratedOnAdd it uses values from a single generator for all tables. This would be similar to having all tables setup to use a single sequence in a relational database. This raises one of the important design principles of our InMemory provider, which is that we are not trying to emulate a relational database. This becomes more important as we start to light up non-relational providers.
If you want to have a database that acts like a relational database, but doesn't have the overhead of I/O, then we'd recommend using an In-Memory SQLite database - http://www.sqlite.org/inmemorydb.html.
We're going to update our testing docs to make the SQLite option more prominent.
来源:https://github.com/aspnet/EntityFrameworkCore/issues/6872
因此,您可以考虑在每次运行测试时手动重置计数器(类似于ALTER TABLE mytable AUTO_INCREMENT = 1;
),或使用帖子中提到的其他sql提供程序。
答案 1 :(得分:0)
只需使用诸如Guid.NewGuid().ToString()
之类的随机名称作为数据库名称,每次都会重置所有内容,因为它将成为内存中一个全新的“数据库”。
var options = new DbContextOptionsBuilder<ServiceContext>()
.UseInMemoryDatabase(databaseName: Guid.NewGuid().ToString()) // Unique name for each test
.Options;