LINQ Contains 语句在复杂对象上用于字符串列表时表现不同
LINQ Contains statement behaves differently when used on a complex object to list of strings
我是白痴吗?这是一个模拟存储库:
Mock<IRepository> repMock = new Mock<IRepository>();
Quote q1 = new Quote { QuoteId = 123 };
Quote q2 = new Quote { QuoteId = 345 };
repMock.Setup(m => m.GetQuotes(It.IsAny<Expression<Func<Quote, bool>>>())).Returns((new List<Quote> { q1, q2 }).AsQueryable);
这是一个 LINQ 语句,它将这些 Id 视为字符串,并获取包含字符串“3”(即两者)的那些:
Assert.AreEqual(2, repMock.Object.GetQuotes(q => q.QuoteId.ToString().Contains("3")).Count());
下面是用于仅获取一个字符串的相同原则 - 但是失败了。它 return 是两个字符串:
Assert.AreEqual(1, repMock.Object.GetQuotes(q => q.QuoteId.ToString().Contains("1")).Count());
然而,如果您将字符串拉出到它们自己的列表中并且 运行 包含反对,它会按预期工作:
List<string> foo = repMock.Object.GetQuotes(q => q.QuoteId.ToString().Contains("3")).Select(q => q.QuoteId.ToString()).ToList();
Assert.AreEqual(1, foo.Where(f => f.Contains("1")).Count());
这是怎么回事?这段代码似乎在生产中确实有效,并按预期过滤了字符串——它只在单元测试中失败了?
编辑:我看到@IvanStoev 在这里所说的逻辑,我将 Mock 设置为 return 两个对象的列表,而不考虑传入的函数。那么我怎样才能得到测试兑现功能?
我觉得问题出在这里
repMock.Setup(m => m.GetQuotes(It.IsAny<Expression<Func<Quote, bool>>>()))
.Returns((new List<Quote> { q1, q2 }).AsQueryable);
我不是很熟悉模型框架,但从逻辑上看,您正在设置 GetQuotes
函数接收谓词始终 return 整个列表,忽略传递的谓词,所以这就是为什么你的测试代码总是 return 2 项。
更新:根据你的编辑,我想你可以使用这样的东西
repMock.Setup(m => m.GetQuotes(It.IsAny<Expression<Func<Quote, bool>>>()))
.Returns((Expression<Func<Quote, bool>> predicate) =>
(new List<Quote> { q1, q2 }).AsQueryable().Where(predicate));
我是白痴吗?这是一个模拟存储库:
Mock<IRepository> repMock = new Mock<IRepository>();
Quote q1 = new Quote { QuoteId = 123 };
Quote q2 = new Quote { QuoteId = 345 };
repMock.Setup(m => m.GetQuotes(It.IsAny<Expression<Func<Quote, bool>>>())).Returns((new List<Quote> { q1, q2 }).AsQueryable);
这是一个 LINQ 语句,它将这些 Id 视为字符串,并获取包含字符串“3”(即两者)的那些:
Assert.AreEqual(2, repMock.Object.GetQuotes(q => q.QuoteId.ToString().Contains("3")).Count());
下面是用于仅获取一个字符串的相同原则 - 但是失败了。它 return 是两个字符串:
Assert.AreEqual(1, repMock.Object.GetQuotes(q => q.QuoteId.ToString().Contains("1")).Count());
然而,如果您将字符串拉出到它们自己的列表中并且 运行 包含反对,它会按预期工作:
List<string> foo = repMock.Object.GetQuotes(q => q.QuoteId.ToString().Contains("3")).Select(q => q.QuoteId.ToString()).ToList();
Assert.AreEqual(1, foo.Where(f => f.Contains("1")).Count());
这是怎么回事?这段代码似乎在生产中确实有效,并按预期过滤了字符串——它只在单元测试中失败了?
编辑:我看到@IvanStoev 在这里所说的逻辑,我将 Mock 设置为 return 两个对象的列表,而不考虑传入的函数。那么我怎样才能得到测试兑现功能?
我觉得问题出在这里
repMock.Setup(m => m.GetQuotes(It.IsAny<Expression<Func<Quote, bool>>>()))
.Returns((new List<Quote> { q1, q2 }).AsQueryable);
我不是很熟悉模型框架,但从逻辑上看,您正在设置 GetQuotes
函数接收谓词始终 return 整个列表,忽略传递的谓词,所以这就是为什么你的测试代码总是 return 2 项。
更新:根据你的编辑,我想你可以使用这样的东西
repMock.Setup(m => m.GetQuotes(It.IsAny<Expression<Func<Quote, bool>>>()))
.Returns((Expression<Func<Quote, bool>> predicate) =>
(new List<Quote> { q1, q2 }).AsQueryable().Where(predicate));