Sqlite 在单元测试期间,避免在EF Core 2.2中使用HasData Seed DbContext
在我的ASP.Net CORE 2.2/EF CORE 2.2 web API应用程序中,我在DbContext中有一个HasData()方法,用我使用的一些标准数据为数据库种子。但是,我不想在运行xUnit测试时使用这些数据 我的单元测试使用Sqlite内存中提供程序,作为该过程的一部分,它需要调用EnsureCreated()。好的,在调用HasData()的ModelCreating()上重新创建()调用,所以我的单元测试上下文现在包含我不想要的所有HasData种子数据。我想用不同的、非常具体的数据来进行单元测试 由于EnsureCreated()为上下文种子,然后我尝试添加特定于单元测试的种子数据,因此最终在test DbContext中出现两组数据,测试失败Sqlite 在单元测试期间,避免在EF Core 2.2中使用HasData Seed DbContext,sqlite,unit-testing,asp.net-core,entity-framework-core,xunit,Sqlite,Unit Testing,Asp.net Core,Entity Framework Core,Xunit,在我的ASP.Net CORE 2.2/EF CORE 2.2 web API应用程序中,我在DbContext中有一个HasData()方法,用我使用的一些标准数据为数据库种子。但是,我不想在运行xUnit测试时使用这些数据 我的单元测试使用Sqlite内存中提供程序,作为该过程的一部分,它需要调用EnsureCreated()。好的,在调用HasData()的ModelCreating()上重新创建()调用,所以我的单元测试上下文现在包含我不想要的所有HasData种子数据。我想用不同的、非
如何在单元测试中绕过HasData调用?您可以始终使用
mock
模拟调用,它将提供一种模拟接口的方法,从而使所述模拟接口的函数调用实际调用您的模拟函数。这将为您提供一种覆盖对HasData
的函数调用的方法
当然,这意味着如果它尚未使用该函数的接口,则必须将其封装在一个接口中
下面是一些有用的例子:和
我还怀疑理论属性和内联数据可能对您有用。
希望这会有所帮助。您可以有条件地不向该方法提供数据,而不是试图绕过HasData() 快速示例-如果将预弹出数据移出,例如“DataInitialiser”类: 然后在基类中设置静态标志:
public abstract class DataInitialiserControl
{
public static bool SkipInitData { get; set; } // ** flag **
}
public abstract class DataInitialiser<T> : DataInitialiserControl
{
public IList<T> Data => SkipInitData ? new List<T>() : GetData();
protected abstract IList<T> GetData();
}
公共抽象类DataInitializerControl
{
公共静态bool SkipInitData{get;set;}/**标志**
}
公共抽象类DataInitializer:DataInitializerControl
{
公共IList数据=>SkipInitData?新列表():GetData();
受保护的抽象IList GetData();
}
您的数据初始化器如下所示:
public class UserDataInitialiser : DataInitialiser<User>
{
protected override IList<User> GetData()
{
return new[]
{
new User {Id = 1, Name = "Bob"}
};
}
}
public类UserDataInitialiser:DataInitialiser
{
受保护的覆盖IList GetData()
{
返回新的[]
{
新用户{Id=1,Name=“Bob”}
};
}
}
然后,您可以在测试初始化中设置静态标志:
public abstract class TestBase
{
protected DbContextOptions<MyContext> DbOptions { get; private set; }
[TestInitialize]
public void InitializeDatabase()
{
// ** SKIP DATA PRE-POP **
DataInitialiserControl.SkipInitData = true;
DbOptions = BuildDbContextOptions(new DbContextOptionsBuilder<MyContext>()).Options;
using (var context = GetContext())
{
context.Database.EnsureCreated();
}
}
[TestCleanup]
public void ClearDatabase()
{
using (var context = GetContext())
{
context.Database.EnsureDeleted();
}
}
}
公共抽象类TestBase
{
受保护的DbContextOptions DbOptions{get;private set;}
[测试初始化]
public void InitializeDatabase()
{
//**跳过数据预处理**
DataInitializerControl.SkipInitData=true;
DbOptions=BuildDbContextOptions(新的DbContextOptionsBuilder()).Options;
使用(var context=GetContext())
{
context.Database.recreated();
}
}
[测试清理]
公共数据库()
{
使用(var context=GetContext())
{
context.Database.EnsureDeleted();
}
}
}
(代码未经测试,但应该或多或少正确)。我也遇到了这个问题,但找不到解决方法。我刚开始在一些测试中使用InMemory数据库提供程序。@我从常规InMemory提供程序开始,但遇到了一个问题,因为它不会重置并行运行的测试之间的标识增量,所以我得到了不可预测的主键ID。啊,这个lol也有问题。你可以通过测试插入实体的PK而不是常量来解决问题。e、 g.
var foo=ctx.Add(new foo())。。。断言相等(foo.Id,实现)代码>应该是EF Core V3上的一个非问题。但是,如果您获得原始问题的解决方案,请告诉我。我们可以在回购协议上打开一个问题,否则:)原始问题的另一个解决方法是明确删除种子,例如ctx.RemoveRange(ctx.Foo)代码>
public abstract class TestBase
{
protected DbContextOptions<MyContext> DbOptions { get; private set; }
[TestInitialize]
public void InitializeDatabase()
{
// ** SKIP DATA PRE-POP **
DataInitialiserControl.SkipInitData = true;
DbOptions = BuildDbContextOptions(new DbContextOptionsBuilder<MyContext>()).Options;
using (var context = GetContext())
{
context.Database.EnsureCreated();
}
}
[TestCleanup]
public void ClearDatabase()
{
using (var context = GetContext())
{
context.Database.EnsureDeleted();
}
}
}