我正在开发使用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
扩展方法?
答案 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软件包时使我的所有方法易于进行单元测试,还不错!