如何在不执行的情况下强制执行EF LINQ查询

时间:2011-04-22 13:57:30

标签: .net unit-testing entity-framework mocking repository-pattern

我有一个很好的解耦应用程序和依赖注入的应用程序,它使用Entity Framework 4.1 CodeFirst通过存储库模式公开IQueryable。在测试存储库客户端时,很容易模拟底层数据存储区,但是没有捕获到某类错误:

存储库客户端可以自由地在存储库返回的内容上层叠自己的LINQ谓词,联接等:

{
     _myRepository.FindAll().Where( x => x.Id == 3 && SomeMethod(x.Name) == "Hello" );
}

这种查询将在一个模拟_myRepository的单元测试中成功,因为mock返回一个内存中的实体集合,而LINQ-to-Objects很乐意调用方法“SomeMethod”。它将对真正的数据存储失败,因为“SomeMethod”不会转换为LINQ-to-Entities中的SQL。

我正在试图找出一种方法,我可以模拟数据集并使真正的EF查询提供程序生成(但不执行)SQL。为什么?因为测试应该很快,我不希望它们尽可能地打到真正的数据库。生成SQL将清除这样的翻译问题。

到目前为止,我还没有弄清楚如何做到这一点,因为在我的单元测试中,我最终无法控制查询何时实现。我想我需要提供我自己的IQueryable版本和各种LINQ Queryable扩展方法,或者尝试通过提供程序机制挂钩(使用几年前做缓存/跟踪提供程序的示例)。这些似乎很多工作。关于如何实现这一点的任何想法?

1 个答案:

答案 0 :(得分:5)

没有办法做到这一点 - 除非您打算构建自己的提供程序,而这又不是解决方案,因为您必须测试真正的提供程序而不是不会在实际代码中使用的自定义实现。我讨论了herehereOne more related answer关于存储库本身。

在没有数据库映射和持久性的情况下,您无法测试数据库映射和持久性。有一些非常奇怪的信念,测试应用程序意味着编写单元测试。这是错误的定义。测试应用程序意味着编写测试和单元测试只是众多测试类型中的一种,但它们无法测试所有测试。您需要将它们与其他类型的测试结合起来。这种情况的正确方法可以是集成测试,它不必每次都运行,但可以在构建服务器上进行调度。