如果我使用EfCore.BulkExtensions

时间:2018-05-13 17:47:05

标签: c# asp.net-core mocking entity-framework-core

我正在开发使用Entity Framework Core 2.0的ASP.Net Core 2.0 API。我正在尝试使用XUnit和Moq构建单元测试但是我遇到了为我的DbContext创建接口的问题,所以我可以在单元测试中模拟它。

目前,我的项目没有为我的上下文使用接口。我将它作为其实现注入我的存储库类。在我的Startup.cs我正在使用services.AddDbContext进行设置。

典型的存储库类构造函数的示例。

    public CompaniesRepository(MyDbContext myDbContext)
    {
        _myDbContext = myDbContext;
    }

Startup.cs示例

        services.AddDbContext<MyDbContext>(options =>
        {
            options.UseSqlServer(Configuration.GetConnectionString("MyDbConnectionString"),
            sqlOptions =>
            {
                sqlOptions.EnableRetryOnFailure(5,TimeSpan.FromSeconds(30),sqlTransientErrors);
            });
        });

这种方法就这样工作得很好。

但是,现在我正在尝试设置单元测试,我希望能够模拟我的上下文,所以我需要为它创建一个接口。

因此,我添加了一个名为MyDbContext IMyDbContext的界面,并根据此blog post by Jerrie Pelser

中的建议将以下代码添加到Startup.cs
        services.AddScoped<IMyDbContext>(provider => provider.GetService<MyDbContext>());

除了一个问题外,这似乎有效。我也在使用Boris Djurdjevic的EFCore.BulkExtensions NuGet,所以,我收到来自我的存储库类的编译错误,现在在他们的构造函数中注入了IMyDbContext接口,说明我的接口是不包含BulkInsert的定义:

  

错误CS1929&#39; IMyDbContext&#39;不包含&#39; BulkInsert&#39;的定义和最好的扩展方法重载&#39; DbContextBulkExtensions.BulkInsert(DbContext,IList,BulkConfig,Action)&#39;需要一个类型为“DbContext&#39;

我认为我需要以某种方式将BulkInsert扩展方法添加到我的IMyDyBontext界面,但我不确定如何正确执行此操作。如果我只是尝试将该方法添加到我的界面,那么我会收到一条错误,说它在我的MyDbContext课程中没有实现,当然。

如何在BulkInsert课程中引用MyDbContext扩展方法?

2 个答案:

答案 0 :(得分:1)

BulkInsert是一种扩展方法。你不能轻易地模拟静态方法

相反,您可以在MyDbContext类中实现它。然后,您可以模拟IMyDbContext进行单元测试。 注意:我没有测试它。

public interface IMyDbContext
{
    void BulkInsert<T>(IList<T> entities, BulkConfig bulkConfig = null,
        Action<decimal> progress = null) where T : class;

}

public class MyDbContext : DbContext, IMyDbContext
{
    public void BulkInsert<T>(IList<T> entities, BulkConfig bulkConfig = null,
        Action<decimal> progress = null) where T : class
    {
        this.BulkInsertOrUpdate(entities, bulkConfig, progress);
    }
}

答案 1 :(得分:0)

我最近在准备使用EF Core BulkExtensions软件包模拟DbContext进行单元测试时遇到了此问题。标记为正确答案的答案是 ALMOST (尽管他们确实说过他们尚未测试其代码)。

以上述方式在DbContext类中实现此功能时,调用BulkInsert方法时,您将收到StackOverflowException。

因此,我开始调试并决定在DbContext类内的方法上设置一个断点,以查看发生了什么。这使我理解了StackOverflowException的原因:由于“ this”关键字的范围,此方法正在调用自身而不是基DbContext类上的方法。

解决方案非常简单,可以通过对MyDbContext实现内部的BulkInsert方法实现进行以下更改来解决:

public async Task BulkInsertAsync<T>(IList<T> entities, BulkConfig bulkConfig = null, Action<decimal> progress = null) where T : class
{
    await ((DbContext)this).BulkInsertAsync<T>(entities, bulkConfig, progress);
}

此外,将以下行添加到您的IMyDbContext接口:

Task BulkInsertAsync<T>(IList<T> entities, BulkConfig bulkConfig = null, Action<decimal> progress = null) where T : class;

这可以确保将“ this”的范围强制转换为基本DbContext类类型,而不是我自己的DbContext实现类型。因此,它不使用自身来调用,而是使用DbContext基类来调用扩展方法。

使用此解决方案,您现在应该能够成功在代码中使用扩展方法,如下所示:

await _context.BulkInsertAsync<User>(users);

希望有人发现这很有用。通过调试弄清楚并确保我可以在使用BulkExtensions软件包时使我的所有方法易于进行单元测试,还不错!