单元测试错误:此函数只能从LINQ到实体调用

时间:2015-02-04 01:44:01

标签: c# linq unit-testing lambda expression

我正在编写一个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 个答案:

答案 0 :(得分:32)

当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;

如果您为此编写了一个好的测试,它将捕获您在几天内通过并比较几个小时的错误。