[英]Mocking DbContext with NSubstitute and Repository is empty or NotImplementedException
I'm trying to mock my DbContext class to do unit tests with NSubstitute but I cannot recover this data from my fake dbcontext through the repository class.我正在尝试模拟我的 DbContext class 以使用 NSubstitute 进行单元测试,但我无法通过存储库 class 从我的假 dbcontext 中恢复这些数据。
I have a generic class (SubstituteDbContext) to create sobe DbSet's and set them to the respective DbSet property in my DbContext.我有一个通用的 class (SubstituteDbContext) 来创建 sobe DbSet 并将它们设置为我的 DbContext 中的相应 DbSet 属性。
I have the code below for each property in DbContext that I want to mock:对于要模拟的 DbContext 中的每个属性,我都有以下代码:
var data = DbSetData.MyData();
var dbSet = SubstituteDbContext.DbSet(data);
dbContext.MyObject.Returns(dbSet);
I create a DbSet to every property with the method below:我使用以下方法为每个属性创建一个 DbSet:
public static DbSet<T> getDbSet<T>(IEnumerable<T> data = null)
where T : class
{
var dbSet = Substitute.For<DbSet<T>, IQueryable<T>>();
if (data != null)
{
var queryable = data.AsQueryable();
((IQueryable<T>)dbSet).Provider.Returns(queryable.Provider);
((IQueryable<T>)dbSet).Expression.Returns(queryable.Expression);
((IQueryable<T>)dbSet).ElementType.Returns(queryable.ElementType);
((IQueryable<T>)dbSet).GetEnumerator().Returns(queryable.GetEnumerator());
((IQueryable<T>)dbSet).AsNoTracking().Returns(queryable);
}
return dbSet;
}
And in my BaseRepository class (my abstract-parent class for every repository) I have some methods like below to get data:在我的 BaseRepository class (每个存储库的我的抽象父 class )我有一些如下方法来获取数据:
public virtual IEnumerable<T> List(Expression<Func<T, bool>> predicate)
{
return DbContext.Set<T>()
.Where(predicate)
.AsEnumerable();
}
But when my debugger runs the List method of BaseRepository I have two possible results (because I tried some variations of the code above):但是当我的调试器运行 BaseRepository 的 List 方法时,我有两个可能的结果(因为我尝试了上面代码的一些变体):
1º I've got System.NotImplementedException
2º The result returned is empty (but
Your SUT invokes DbContext.Set<T>()
however you only set up dbContext.MyObject.Returns(dbSet)
.您的 SUT 调用DbContext.Set<T>()
但是您只设置dbContext.MyObject.Returns(dbSet)
。 You'll need to set up the former.您需要设置前者。
Like @rgvlee said I wasn't setting up DbSet correctly.就像@rgvlee 说我没有正确设置 DbSet 一样。
I've changed my getDbSet<T>
generic method for setDbSet<T>
because I'm not returning the mocked DbSet anymore and setting it im DbContext in my another generic method with SetValue (from reflection).我已经更改了 setDbSet<T> 的setDbSet<T>
getDbSet<T>
泛型方法,因为我不再返回模拟的 DbSet 并在我的另一个泛型方法中使用 SetValue(来自反射)将其设置为 im DbContext。
Now I'm setting up the generic Set<T>
property from my mocked DbContext directly in setDbSet<T>
method and isn't necessary to set it directly with reflection.现在我直接在setDbSet<T>
方法中从我的模拟 DbContext 设置通用Set<T>
属性,并且不需要直接使用反射设置它。
Below the code from the new setDbSet<T>()
(that was getDbSet<T>()
):在新setDbSet<T>()
的代码下方(即getDbSet<T>()
):
public static void setDbSet<T>(DbContext dbContext, IEnumerable<T> data = null)
where T : class
{
var dbSet = Substitute.For<DbSet<T>, IQueryable<T>>();
if (data != null)
{
var queryable = data.AsQueryable();
((IQueryable<T>)dbSet).Provider.Returns(queryable.Provider);
((IQueryable<T>)dbSet).Expression.Returns(queryable.Expression);
((IQueryable<T>)dbSet).ElementType.Returns(queryable.ElementType);
((IQueryable<T>)dbSet).GetEnumerator().Returns(queryable.GetEnumerator());
((IQueryable<T>)dbSet).AsNoTracking().Returns(queryable);
}
dbContext.Set<T>().Returns(dbSet);
}
And In my generic method that calls setDbSet<T>()
I've removed the line below where I was setting up that mocked dbSet returned from getDbSet<T>()
in my DbContext.在我调用setDbSet<T>()
的通用方法中,我删除了下面的行,我在 DbContext 中设置从getDbSet<T>()
返回的模拟 dbSet。
propertyInfo.SetValue(dbContext, dbSet);
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.