【发布时间】:2020-10-11 09:01:13
【问题描述】:
我正在编写单元测试,需要模拟实体框架的 .FromSqlRaw 方法。在被测类中执行该方法时,会抛出以下异常:
System.InvalidOperationException:没有方法 'FromSqlOnQueryable' 类型 'Microsoft.EntityFrameworkCore.RelationalQueryableExtensions' 匹配指定的参数。
以下是被测类:
public class PowerConsumptionRepository : IPowerConsumptionRepository
{
private readonly IDatabaseContext _databaseContext;
private readonly IDateTimeHelper _dateTimeHelper;
public PowerConsumptionRepository(IDatabaseContext databaseContext, IDateTimeHelper dateTimeHelper)
{
_databaseContext = databaseContext;
_dateTimeHelper = dateTimeHelper;
}
public List<IntervalCategoryConsumptionModel> GetCurrentPowerConsumption(string siteId)
{
var currentDate = _dateTimeHelper
.ConvertUtcToLocalDateTime(DateTime.UtcNow, ApplicationConstants.LocalTimeZone)
.ToString("yyyy-MM-dd");
var currentDateParameter = new SqlParameter("currentDate", currentDate);
var measurements = _databaseContext.IntervalPowerConsumptions
.FromSqlRaw(SqlQuery.CurrentIntervalPowerConsumption, currentDateParameter)
.AsNoTracking()
.ToList();
return measurements;
}
}
单元测试:
public class PowerConsumptionRepositoryTests
{
[Fact]
public void TestTest()
{
var data = new List<IntervalCategoryConsumptionModel>
{
new IntervalCategoryConsumptionModel
{
Id = 1,
Hvac = 10
},
new IntervalCategoryConsumptionModel
{
Id = 1,
Hvac = 10
}
}.AsQueryable();
var dateTimeHelper = Substitute.For<IDateTimeHelper>();
dateTimeHelper.ConvertUtcToLocalDateTime(Arg.Any<DateTime>(), Arg.Any<string>()).Returns(DateTime.Now);
var mockSet = Substitute.For<DbSet<IntervalCategoryConsumptionModel>, IQueryable<IntervalCategoryConsumptionModel>>();
((IQueryable<IntervalCategoryConsumptionModel>)mockSet).Provider.Returns(data.Provider);
((IQueryable<IntervalCategoryConsumptionModel>)mockSet).Expression.Returns(data.Expression);
((IQueryable<IntervalCategoryConsumptionModel>)mockSet).ElementType.Returns(data.ElementType);
((IQueryable<IntervalCategoryConsumptionModel>)mockSet).GetEnumerator().Returns(data.GetEnumerator());
var context = Substitute.For<IDatabaseContext>();
context.IntervalPowerConsumptions = (mockSet);
var repo = new PowerConsumptionRepository(context, dateTimeHelper);
var result = repo.GetCurrentPowerConsumption(Arg.Any<string>());
result.Should().NotBeNull();
}
}
【问题讨论】:
-
致quote the EF Core documentation:我们从不尝试模拟 DbContext 或 IQueryable。这样做是困难的、麻烦的和脆弱的。 不要这样做。(他们的重点。)
-
对。我明白。但这是否意味着我不能对其进行单元测试?我无法使用内存数据库,因为
.FromSqlRaw执行 SQL 查询。 -
那不是问题吗?您正在测试一个与您的数据库高度耦合的类,现在您想抽象该数据库但发现它非常困难或不可能?要正确测试
PowerConsumptionRepository,您可能应该使用“真实”数据库。我最近看到了 Jimmy Bogard 的帖子Avoid In-Memory Databases for Tests,它可能会让你对这个问题有更多的看法。 -
或者检查生产代码中的提供者类型。
标签: c# asp.net-core entity-framework-core xunit nsubstitute