我可以在不实际执行 LINQ 查询的情况下测试它的构造吗

jus*_*mer 5 .net tdd linq-to-entities unit-testing

我听说在测试 EF 时,由于 LINQ to Objects 和 LINQ to Entities 提供程序之间的差异,您需要针对实时数据库使用集成测试。

为什么我们不能在不实际执行查询的情况下对查询的构造进行单元测试?我本以为你可以以某种方式将你的 IQueryable 连接到 LINQ to Entities 提供程序,并确认 SQL 已正确生成(使用类似 ToTraceString 之类的东西,它不会执行实际的查询)。

我想象代码是这样的(这个查询在 L2O 中运行良好,但在 L2E 中则不行):

    <Test()> _
    Public Sub Query_Should_Build_Against_L2E()
        Dim testQuery = From d In myDb
                        Where d.Status = CType(Status.Ready, Integer)

        testQuery.SetQueryProvider("L2E")

        Assert.DoesNotThrow(testQuery.ToTraceString())
    End Sub
Run Code Online (Sandbox Code Playgroud)

编辑

我尝试按如下方式实施 GertArnold 的解决方案:

Dim context As New Context("Data Source=fakedbserver;Initial Catalog=fakedb;Persist Security Info=True;")
Dim result = context.myTable.Where(Function(d) d.Status=True)
Run Code Online (Sandbox Code Playgroud)

这会引发ProviderIncompatibleException消息“从数据库获取提供程序信息时发生错误。这可能是由实体框架使用不正确的连接字符串引起的。检查内部异常以获取详细信息并确保连接字符串正确。” 这是完整的异常链:

System.Data.ProviderIncompleteException:从数据库获取提供程序信息时发生错误。这可能是由于实体框架使用了不正确的连接字符串造成的。检查内部异常的详细信息并确保连接字符串正确。

System.Data.ProviderInknownException:提供程序未返回 ProviderManifestToken 字符串。

System.InvalidOperationException :此操作需要连接到“master”数据库。无法创建与“master”数据库的连接,因为原始数据库连接已打开并且凭据已从连接字符串中删除。提供未打开的连接。

System.Data.SqlClient.SqlException:建立与 SQL Server 的连接时发生与网络相关或特定于实例的错误。服务器未找到或无法访问。验证实例名称是否正确以及 SQL Server 是否配置为允许远程连接。(提供程序:命名管道提供程序,错误:40 - 无法打开与 SQL Server 的连接)

Ger*_*old 2

将 IQueryable 连接到 LINQ to Entities 提供程序

问题是:哪个IQueryable?接口本身并没有什么。使用 EF,您要处理的是实现的类IQueryable,但除此之外还可以做更多的事情。事实上,它们完全有能力与上下文和已经附加在引擎盖下的查询提供程序合作。IQueryable.IQueryProvider是一个只读属性,因此它是由创建特定IQueryable实现的工厂设置的。

因此,您testQuery将是一个ObjectQuery,因为它取自其中,myDb除了 EF 上下文之外,不能是其他任何东西。

为什么我们不能在不实际执行查询的情况下对查询的构造进行单元测试?

这不是你真正的问题吗?事实上,我什至想知道您是否需要一个不同的查询提供程序。我认为您会希望 EF 查询提供程序像这样工作,否则仍然不能保证 EF 的工作方式相同。

无论如何,您可以创建一个在其连接字符串中包含虚假数据库名称的上下文(以确保它不会连接)并检查((ObjectQuery)testQuery).ToTraceString(). 只要不迭代就可以了testQuery。我可以想象,当查询在复杂的执行路径中组成时,这样的测试有一定的价值。(但我宁愿避免这种情况)。