你怎么能对这个糟糕的Linq-To-SQL谓词进行单元测试?

时间:2015-03-25 19:59:06

标签: unit-testing linq-to-sql lambda predicate

给出以下示例代码:

Table<Person> tableToQuery = MethodThatGetsReferenceToPersonTable();
string searchType = "NonUser";
IQueryable<Person> queryResults = tableToQuery.Where(p =>
    (p.IsMale == false) && // exclude male people
    type.Equals("User", StringComparison.OrdinalIgnoreCase)
        ? p.User != null : p.User == null);

我是L2S的新手,但确实对EntityFramework有一些经验。我不希望上述查询在像EF这样的ORM中正常工作,因为在谓词的三元表达式中调用了type.Equals。我宁愿期望EF抛出异常,因为它无法将谓词的那部分转换为(SQL)存储表达式。

使用L2S时,.Where似乎正在返回数据,但p.Male == truetype == "NonUser不排除项目。我已经修复了上面的代码,将type.Equals三元素从谓词中拉出并返回正确的结果,现在我正在尝试编写一个测试来断言正确的结果。我遇到的问题是L2S代码实际上落后于IRepository<Person>接口。

所以实际的代码看起来更像是这样:

string searchType = "NonUser";
ICriteria<Person> query = new Query<Person>(p =>
  (p.IsMale == false) && // exclude male people
  type.Equals("User", StringComparison.OrdinalIgnoreCase)
      ? p.User != null : p.User == null);
IQueryable<Person> = _peopleRepository.FindByQuery(query)

... _peopleRepository实现只是将query.Predicate作为参数传递给L2S Table<Person>.Where

问题:

  1. 由于lambda谓词中的三元表达式,L2S Table<Person>.Where没有返回正确的结果是否正确?我假设是这样的,因为根据ICriteria<Person>的值生成单独的searchType对象生成三元组正在产生正确的结果。但是我不确定这是因为L2S无法将三元转换为商店表达式,或者是否由其他原因引起。

  2. 由于测试中的方法取决于IRepository<Person>实例,我怎样才能真正围绕此实例编写单元测试?在单元测试中模拟IRepository<Person>将不允许我们测试lambda对真实底层数据的影响。创建由某种FakePersonRepository支持的IList<Person>不会显示实际缺陷,因为上面带有三元表达式的lambda使用linq-to-objects返回预期结果。有没有什么方法可以模拟L2S的一部分,以便我们可以使用lambda生成SQL,然后针对它编写断言?

  3. 这只是我们与集成测试和带有连接字符串的实际L2S上下文有关,而不能正确进行单元测试吗?我对“集成测试”的定义意味着“使用某种连接字符串连接到与测试运行器分开运行的实际数据库”,而“单元测试”意味着“在测试运行程序中执行所有操作”。

1 个答案:

答案 0 :(得分:1)

  
      
  1. L2S(...)没有返回正确的结果是否正确
  2.   

它确实会返回正确的结果,但不会返回您期望的结果,因为您将查询视为人而不是编译器。后者读到了这个:

tableToQuery.Where(p =>
    ((p.IsMale == false) && type.Equals("User", StringComparison.OrdinalIgnoreCase))
        ? p.User != null
        : p.User == null);

我们人类倾向于阅读这个:

tableToQuery.Where(p => (p.IsMale == false) && 
     (type.Equals("User", StringComparison.OrdinalIgnoreCase)
        ? p.User != null
        : p.User == null));
  

2./3。我怎么能真正围绕这个进行单元测试?

模拟和单元测试几乎是不可能的。当我想测试数据层的行为时,我坚持使用集成测试。对于实体框架,我收集了集成测试here的一些原因。其中大部分也适用于LINQ-to-SQL。