如何在没有数据库的情况下验证LINQ可查询

时间:2016-05-18 18:55:17

标签: c# entity-framework linq unit-testing iqueryable

注意:

我愿意接受关于这个问题的更好标题的建议。

背景:

对于使用Entity Framework足够长的任何人来说,您必然会遇到生成的IQueryable<T>无法由数据库执行的问题。这源于IQueryable<T>除了内存实现(例如LINQ to objects)之外不可能完全实现的事实。诸如C#方法调用和使用Single / SingleOrDefault作为非最终查询操作之类的事情在发送到真实IQueryProvider时会导致失败(例如对于MSSQL或Oralce),但是通过在单元测试中。

我目前知道如何测试这些情况的唯一方法是实际运行该软件。虽然我同意该软件绝对应该作为编写新查询(或一般新代码)的一部分来完成,但如果使用单元测试可以找到这些类型的错误会很有帮助。导致我在这里的事件是发现了一个新的错误,我确信开发人员是一个无辜和安全的变化。更进一步,通过大量的单位测试给出了一种虚假的自信感。

问题:

是否可以验证生成的IQueryable<T>实际上是否可以通过单元测试在特定的数据库技术(MSSQL,Oracle,等等)上运行?

示例:

使用C#方法调用可查询:

var result = (
    from a in session.Query<A>
    where a.Field == SomeFunction(a)
    select a
    ).ToList();

由于数据库无法执行C#代码的明显原因,这将失败。

单个

可查询
var result = (
    from a in session.Query<A>
    where a.Field == session.Query<B>().Single().Field
    select a
    ).ToList();

由于使用single作为非最终查询操作,这将失败。

还有其他情况,但我认为以上两个例子描述了我试图能够检测到的内容。

2 个答案:

答案 0 :(得分:1)

有了这个查询

var query = 
    from a in session.Query<A>
    where a.Field == session.Query<B>().Single().Field
    select a;

执行

query.ToString();

如果无法将其转换为正确的SQL查询,则会抛出异常。

答案 1 :(得分:0)

您必须模拟session.Query<A>等属性,并在单元测试中发送enumerable\queryable集合。根据我的经验,这样做的好处还不足以创建和维护这些类型的测试,特别是当您有涉及多个表和层的复杂查询时。

我发现有用(用于测试实际查询)是使用specflow等框架进行更多集成测试,您可以使用它来轻松设置测试数据并执行集成测试,同时测试软件行为的级别高于单元测试。但是当然这些应该适用于真正的数据库,所以你可能不希望它们开始。