单元测试错误:此函数只能从 LINQ 调用到实体
Posted
技术标签:
【中文标题】单元测试错误:此函数只能从 LINQ 调用到实体【英文标题】:Unit test error : This function can only be invoked from LINQ to Entities 【发布时间】:2015-04-03 10:14:47 【问题描述】:我正在编写一个 MVC 5 互联网应用程序,我的表达式如下:
public Expression<Func<Account, bool>> IsExpiresDateTimeLessThanMinimumDaysLeftInFreeTrialSubscription(int minimumDaysLeftInSubscriptionForEmail)
return Account => System.Data.Entity.DbFunctions.DiffHours(Account.freeTrialEndDate, DateTime.UtcNow) < minimumDaysLeftInSubscriptionForEmail;
从数据库中检索数据时,上述表达式正确完成。但是,在编写使用上述表达式的单元测试时,出现以下错误:
此函数只能从 LINQ to Entities 调用
我推测这是因为System.Data.Entity.DbFunctions.DiffHours
函数将expression
转换为只有数据库系统才能理解的代码。
由于上述事实,当使用使用List
而不是DbSet
的模拟存储库时,是否可以对上述表达式进行单元测试?如果没有,我应该如何对使用expression
的任何代码进行单元测试?是否可以对expression
进行单元测试?
提前致谢。
【问题讨论】:
【参考方案1】:当 EF 生成 SQL 代码时,唯一重要的是 System.Data.Entity.DbFunction
属性。方法体抛出异常,但在使用真实数据库时从不调用。
要对此进行测试,您可以使用DbFunction
属性和实现创建自己的方法。针对数据库运行时,EF 将生成 SQL 并忽略您的代码。运行单元测试时,您的代码将被执行。
你的方法看起来像这样:
public static class TestableDbFunctions
[System.Data.Entity.DbFunction("Edm", "DiffHours")]
public static int? DiffHours(DateTime? dateValue1, DateTime? dateValue2)
if (!dateValue1.HasValue || !dateValue2.HasValue)
return null;
return (int)((dateValue2.Value - dateValue1.Value).TotalHours);
比较代码只是举例,您需要确保它与 SQL 行为匹配,否则您的测试将无效。
一旦你有了这个,只需更改你的代码以使用新方法:
return Account => TestableDbFunctions.DiffHours(Account.freeTrialEndDate, DateTime.UtcNow) < minimumDaysLeftInSubscriptionForEmail;
如果您为此编写了一个好的测试,它将捕获您在几天内通过并比较几个小时的错误。
【讨论】:
上面的代码是否自动判断代码是针对数据库还是列表运行?如果没有,可以将其编码到函数中吗?我问这个是因为表达式是 where 子句中的许多表达式之一。 它将自动针对数据库或列表运行正确的行为。实际的确定是通过 IQueryable 的实现来完成的。 ListSqlFunctions.DatePart()
,我使用了属性[DbFunction("SqlServer", "DATEPART")]
(注意故意大写的第二个参数以精确匹配this value)。以上是关于单元测试错误:此函数只能从 LINQ 调用到实体的主要内容,如果未能解决你的问题,请参考以下文章
Linq 错误:“where”条件无效。实体成员正在调用无效的属性或方法