c# - 尝试编写测试时的 NSubstitute、DbContext 和一个奇怪的问题
问题描述
我有一个很好的模拟 DbSet的扩展方法:
public static class DbSetExtensions
{
public static DbSet<T> ToDbSet<T>(this IEnumerable<T> data) where T : class
{
var queryData = data.AsQueryable();
var dbSet = Substitute.For<DbSet<T>, IQueryable<T>>();
((IQueryable<T>)dbSet).Provider.Returns(queryData.Provider);
((IQueryable<T>)dbSet).Expression.Returns(queryData.Expression);
((IQueryable<T>)dbSet).ElementType.Returns(queryData.ElementType);
((IQueryable<T>)dbSet).GetEnumerator().Returns(queryData.GetEnumerator());
return dbSet;
}
}
我试图在这样的上下文文件中使用它:
public class DatabaseContextContext<T> where T: DatabaseContextContext<T>
{
public DatabaseContext DatabaseContext;
protected DatabaseContextContext()
{
DatabaseContext = Substitute.For<DatabaseContext>();
}
public T WhenListSucceeds<TEntity>(IList<TEntity> data) where TEntity : class
{
var dbSet = data.ToDbSet();
DatabaseContext.Set<TEntity>().Returns(dbSet);
return (T)this;
}
public T WhenGetSucceeds<TEntity>(TEntity entity) where TEntity : class
{
var dbSet = new List<TEntity> { entity }.ToDbSet();
DatabaseContext.Set<TEntity>().Returns(dbSet);
return (T)this;
}
}
当我对此方法运行测试时,它失败了:
public ActionResult<List<Formula>> ListFormulas(int id) =>
Ok(_databaseContext.Formulas.Where(m => m.AttributeId.Equals(id)).ToList());
带有此错误消息:
System.InvalidCastException:无法将“Castle.Proxies.ObjectProxy_3”类型的对象转换为“Microsoft.EntityFrameworkCore.Metadata.Internal.Model”类型。
所以我试着把它分解一下。首先,我将方法更改为:
public ActionResult<List<Formula>> ListFormulas(int id)
{
var s = _databaseContext.Formulas;
var x = _databaseContext.Formulas.ToList();
var t = _databaseContext.Formulas.Where(m => m.AttributeId.Equals(id)).ToList();
return Ok(t);
}
但是在调试时,代码并没有通过该ToList()
方法。我仍然遇到同样的问题。因此,我将代码更改为:
public ActionResult<List<Formula>> ListFormulas(int id)
{
var p = _databaseContext.Set<Formula>();
var q = p.ToList();
var s = _databaseContext.Formulas;
var x = _databaseContext.Formulas.ToList();
var t = _databaseContext.Formulas.Where(m => m.AttributeId.Equals(id)).ToList();
return Ok(t);
}
前 3 行代码有效,但一旦到达该行var x = _databaseContext.Formulas.ToList();
,它就会失败。有谁知道为什么?
这是测试:
[TestFixture]
public class ListShould
{
[Test]
public void ReturnList()
{
// Assemble
var services = GenericOrderProviderContext.GivenServices();
var provider = services.WhenCreateOrderProvider();
services.DatabaseContext.Attributes = new List<Attribute>().ToDbSet();
services.DatabaseContext.Set<Attribute>().ReturnsForAnyArgs(_ => new List<Attribute>().ToDbSet());
// Act
var result = provider.List();
// Assert
result.Failure.Should().BeFalse();
result.Result.Count().Should().Be(0);
}
}
解决方案
.Formulas
当未配置db 上下文属性时,我能够重现您的错误。如果您同时使用两者.Set<Formula>()
,则.Formulas
需要同时配置两者。
我确实注意到您为 db set 枚举器设置的
((IQueryable<T>)dbSet).GetEnumerator().Returns(queryData.GetEnumerator());
导致我之前看到的一些行为,其中只有第一个 ToList() 调用返回结果。如果你明白了,你可能需要重置枚举器或使用Func<CallInfo, IEnumerator<Formula>>
Returns
重载。