您如何针对这个糟糕的 Linq-To-SQL 谓词进行单元测试?

How could you unit test against this bad Linq-To-SQL 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 似乎是 returning 数据,但它不排除 type == "NonUserp.Male == true 的项目。我已经修复了上面的代码以将 type.Equals 三元从谓词中拉出并得到 return 正确的结果,现在我正在尝试编写一个测试来断言正确的结果。我 运行 遇到的问题是 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 未 return 得到正确的结果是否正确?我假设是这样,因为根据 searchType 的值将三元组取出生成单独的 ICriteria<Person> 对象会产生正确的结果。但是我不太确定这是因为L2S无法将三元转换为存储表达式,还是其他原因造成的。

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

  3. 这只是我们必须要做的集成测试和带有连接字符串的实际 L2S 上下文,而不能正确进行单元测试吗?我对 "integration test" 的定义表示 "connect to an actual database running in a separate process from the test runner using some kind of connection string",而 "unit test" 表示 "do everything in the test runner process"。

  1. Is it correct that the L2S (...) is not returning the correct results

它确实 return 正确了结果,但不是您期望的结果,因为您是作为一个人而不是作为一个编译器来阅读查询的。后者是这样写的:

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. how could I actually write a unit test around this?

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