在单元测试期间避免在EF Core 2.2中使用HasData Seed DbContext

时间:2019-03-26 20:52:32

标签: 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内存提供程序,并且作为该过程的一部分,它需要调用GuaranteeCreated()。好吧,EnsureCreated()调用了OnModelCreating(),后者调用了HasData(),所以我的单元测试上下文现在包含我不需要的所有HasData种子数据。我想用不同的,非常具体的数据作为单元测试的种子。

因为确保环境创建了种子,然后尝试添加特定于单元测试的种子数据,所以最终在测试DbContext中使用了这两组数据,并且测试失败。

如何为单元测试绕过HasData调用?

2 个答案:

答案 0 :(得分:0)

您始终可以使用Mock模拟调用,这将提供一种模拟使其成为接口的方法,因此上述模拟接口的函数调用实际上将在调用您的模拟函数。这将为您提供一种方法来覆盖对HasData的函数调用。

当然,这意味着如果尚未为该功能使用接口,则必须将其包装为一个。

以下是一些有用的模拟示例:writing unit tests with NUnit and Moqan introduction to unit testing with mocks(using moq)

我还怀疑Theory属性和内联数据可能对您有用。     Creating parameterized tests in xUnit

希望有帮助。

答案 1 :(得分:0)

代替尝试绕过HasData(),您可以有条件地不向该方法提供数据。

快速示例-如果您将预弹出数据移至例如“ DataInitialiser”类:

 builder.HasData(new UserDataInitialiser().Data); 

然后在基类中设置一个静态标志:

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();
}

您的DataInitialisers看起来像这样:

public class UserDataInitialiser : DataInitialiser<User>
{
    protected override IList<User> GetData()
    {
        return new[]
        {
            new User {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();
        }
    }
}

(代码未经测试,但应大致正确)。