使用 NSubstitute 和 Repository 模拟 DbContext 为空或 NotImplementedException
Mocking DbContext with NSubstitute and Repository is empty or NotImplementedException
我正在尝试模拟我的 DbContext class 以使用 NSubstitute 进行单元测试,但我无法通过存储库 class.
从我的假 dbcontext 中恢复此数据
我有一个通用的 class (SubstituteDbContext) 来创建 sobe DbSet 并将它们设置为我的 DbContext 中的相应 DbSet 属性。
对于 DbContext 中我想要模拟的每个 属性,我都有下面的代码:
var data = DbSetData.MyData();
var dbSet = SubstituteDbContext.DbSet(data);
dbContext.MyObject.Returns(dbSet);
我使用以下方法为每个 属性 创建一个 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;
}
并且在我的 BaseRepository class(每个存储库的抽象父级 class)中,我有一些如下所示的方法来获取数据:
public virtual IEnumerable<T> List(Expression<Func<T, bool>> predicate)
{
return DbContext.Set<T>()
.Where(predicate)
.AsEnumerable();
}
但是当我的调试器运行 BaseRepository 的 List 方法时,我有两个可能的结果(因为我尝试了上面代码的一些变体):
1º I've got System.NotImplementedException
2º The result returned is empty (but
您的 SUT 调用 DbContext.Set<T>()
,但您只设置了 dbContext.MyObject.Returns(dbSet)
。您需要设置前者。
就像@rgvlee 说的那样,我没有正确设置 DbSet。
我已经为 setDbSet<T>
更改了我的 getDbSet<T>
通用方法,因为我不再返回模拟的 DbSet 并在我的另一个通用方法中使用 SetValue(来自反射)将其设置为 im DbContext。
现在我直接在 setDbSet<T>
方法中从我的模拟 DbContext 设置通用 Set<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);
}
并且在我调用 setDbSet<T>()
的通用方法中,我删除了下面我设置从 DbContext 中的 getDbSet<T>()
返回的模拟 dbSet 的行。
propertyInfo.SetValue(dbContext, dbSet);
我正在尝试模拟我的 DbContext class 以使用 NSubstitute 进行单元测试,但我无法通过存储库 class.
从我的假 dbcontext 中恢复此数据我有一个通用的 class (SubstituteDbContext) 来创建 sobe DbSet 并将它们设置为我的 DbContext 中的相应 DbSet 属性。
对于 DbContext 中我想要模拟的每个 属性,我都有下面的代码:
var data = DbSetData.MyData();
var dbSet = SubstituteDbContext.DbSet(data);
dbContext.MyObject.Returns(dbSet);
我使用以下方法为每个 属性 创建一个 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;
}
并且在我的 BaseRepository class(每个存储库的抽象父级 class)中,我有一些如下所示的方法来获取数据:
public virtual IEnumerable<T> List(Expression<Func<T, bool>> predicate)
{
return DbContext.Set<T>()
.Where(predicate)
.AsEnumerable();
}
但是当我的调试器运行 BaseRepository 的 List 方法时,我有两个可能的结果(因为我尝试了上面代码的一些变体):
1º I've got System.NotImplementedException
2º The result returned is empty (but
您的 SUT 调用 DbContext.Set<T>()
,但您只设置了 dbContext.MyObject.Returns(dbSet)
。您需要设置前者。
就像@rgvlee 说的那样,我没有正确设置 DbSet。
我已经为 setDbSet<T>
更改了我的 getDbSet<T>
通用方法,因为我不再返回模拟的 DbSet 并在我的另一个通用方法中使用 SetValue(来自反射)将其设置为 im DbContext。
现在我直接在 setDbSet<T>
方法中从我的模拟 DbContext 设置通用 Set<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);
}
并且在我调用 setDbSet<T>()
的通用方法中,我删除了下面我设置从 DbContext 中的 getDbSet<T>()
返回的模拟 dbSet 的行。
propertyInfo.SetValue(dbContext, dbSet);