您如何针对这个糟糕的 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 == "NonUser
时 p.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
。
问题:
由于 lambda 谓词中的三元表达式,L2S Table<Person>.Where
未 return 得到正确的结果是否正确?我假设是这样,因为根据 searchType
的值将三元组取出生成单独的 ICriteria<Person>
对象会产生正确的结果。但是我不太确定这是因为L2S无法将三元转换为存储表达式,还是其他原因造成的。
由于被测方法依赖于一个 IRepository<Person>
实例,我怎么能围绕它编写单元测试呢?在单元测试中模拟 IRepository<Person>
不允许我们测试 lambda 对真实基础数据的影响。创建由某种 IList<Person>
支持的 FakePersonRepository
也不会揭示实际缺陷,因为上面带有三元表达式的 lambda returns 使用 linq-to-objects 的预期结果。有什么方法可以模拟 L2S 的一部分,以便我们可以使用 lambda 生成 SQL,然后针对它编写断言?
这只是我们必须要做的集成测试和带有连接字符串的实际 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"。
- 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。
给定以下示例代码:
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 == "NonUser
时 p.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
。
问题:
由于 lambda 谓词中的三元表达式,L2S
Table<Person>.Where
未 return 得到正确的结果是否正确?我假设是这样,因为根据searchType
的值将三元组取出生成单独的ICriteria<Person>
对象会产生正确的结果。但是我不太确定这是因为L2S无法将三元转换为存储表达式,还是其他原因造成的。由于被测方法依赖于一个
IRepository<Person>
实例,我怎么能围绕它编写单元测试呢?在单元测试中模拟IRepository<Person>
不允许我们测试 lambda 对真实基础数据的影响。创建由某种IList<Person>
支持的FakePersonRepository
也不会揭示实际缺陷,因为上面带有三元表达式的 lambda returns 使用 linq-to-objects 的预期结果。有什么方法可以模拟 L2S 的一部分,以便我们可以使用 lambda 生成 SQL,然后针对它编写断言?这只是我们必须要做的集成测试和带有连接字符串的实际 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"。
- 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。