如何模拟LINQ to Entities助手,例如'SqlFunctions.StringConvert()'

Chi*_*han 4 c# unit-testing moq mocking entity-framework-4

我正在使用EF 4并尝试使用Moq对以下行进行单元测试:

var convertError = models
             .Where(x => SqlFunctions.StringConvert((decimal?) (x.convert ?? 0)) == "0")
             .Any();
Run Code Online (Sandbox Code Playgroud)

SqlFunctions.StringConvert()如果它检测到上下文被模拟,它似乎会抛出.

它给出了一个错误说:

只能从LINQ到实体调用此函数

是否有可能告诉SqlFunctions.StringConvert返回一个模拟对象,以便我可以摆脱这个错误?

Lad*_*nka 5

不,这是不可能的,因为函数的实现看起来像:

[EdmFunction("SqlServer", "STR")]
public static string StringConvert(decimal? number, int? length)
{
    throw EntityUtil.NotSupported(Strings.ELinq_EdmFunctionDirectCall);
}
Run Code Online (Sandbox Code Playgroud)

你不能使用Moq伪造这个功能.您需要更强大的模拟框架,它允许您替换静态函数调用 - 可能是Microsoft Fakes,TypeMock Isolator或JustMock.

或者你需要考虑你的测试方法,因为模仿上下文是错误的想法.你应该改为:

var convertError = myQueryProvider.ConvertQuery(x.convert); 
Run Code Online (Sandbox Code Playgroud)

queryProvider隐藏查询的可模拟类型在哪里?查询是与数据库相关的逻辑,应该针对真实数据库进行测试.您的查询周围的代码是您的应用程序逻辑,它应该是单元测试的 - 正确测试它们的最佳解决方案只是通过某个接口(在这种情况下查询提供程序,但人们经常使用完整的特定存储库)将它们分开.这个原则来自于关注点的分离 - 查询执行是一个单独的问题,因此它被放置在自己的方法中,该方法是单独测试的.


小智 5

我所做的是提供我自己的DbFunction实现,使得单元测试中的LINQ To Objects使用简单的.NET实现,而LINQ To EF在运行时使用DbFunctionAttribute,方式与System.Data.Entity.DbFunctions相同.我曾想过嘲笑DbFunctions但是,LINQ to Objects实现很有用并且工作正常.这是一个例子:

public static class DbFunctions
{
    [DbFunction("Edm", "AddMinutes")]
    public static TimeSpan? AddMinutes(TimeSpan? timeValue, int? addValue)
    {
        return timeValue == null ? (TimeSpan?)null : timeValue.Value.Add(new TimeSpan(0, addValue.Value, 0));
    }
}
Run Code Online (Sandbox Code Playgroud)