一个返回自身的iquerable

本文关键字:iquerable 返回 一个 | 更新日期: 2023-09-27 17:54:01

我正在使用模拟IQueryable(使用Moq)设置一个测试,我想在.Where()被调用时返回它自己:

[SetUp]
public void Setup() {
    mockPocos = new Mock<IQueryable<Poco>>();
    mockPocos.Setup(foo => foo.Where(It.IsAny<Expression<Func<Poco, bool>>>()))
        .Returns(mockPocos.Object);
}

(这样,我可以模拟像.Count这样的方法/属性,并且知道无论测试的方法在IQueryable上运行查询多少次,它都会返回我可以控制的值。)

这可以编译,但是当我运行它时,我得到了这个异常:

Tests.PocoTest.TestPocoQueryable:
SetUp : System.NotSupportedException : Expression references a method that does not belong to the mocked object: foo => foo.Where<Poco>(It.IsAny<Expression`1>())

我怎样才能使它工作?


编辑:作为对评论的回应,这就是我想这样使用Moq的原因。

在我测试的方法中,我有这样的代码:

public int[] MethodToTest(IQueryable<Poco> pocos, MockableDependency dependency)
{
    var mostRecentUpdate = (from poco in pocos
                                select poco.Date_Last_Updated).Max();
    var recentPocos = pocos.Where(x => x.Date_Last_Updated.CompareTo(mostRecentUpdate) >= 0);
    ///...snip...
    result[0] = SomePrivateCalculation(recentPocos.Count);
    result[1] = dependency.DoADifferentCalculation(recentPocos);
}

我已经嘲笑了MockableDependency,所以我实际上不需要担心pocos中的Poco是什么。但是,我希望能够控制recentPocos.Count的值是什么,并且我希望能够知道,在访问.Count之前,无论在pocos上运行多少查询,它都会返回相同的值。

一个返回自身的iquerable

MattiasG暗示了解决方案。您应该提供一个可查询的pocos,它将始终生成一个带有已知结果的查询,并给出您期望的。count。

所以代码中没有显示的是正确的;传递pocos的方法也应该被模拟,以提供可以对其进行正确断言的数据。

很难找到一个好的测试平衡。这真的是一种艺术形式。但是如果你正在使用moq,你应该关注高阶的"工作单元",而不是单个方法内部发生的事情。

换句话说。假设你设法让Count总是返回5。然后你有一个测试在依赖方法中检查Count是否为5。它是。你完成了什么?好吧,你可以断言Count将返回一个int(我们知道这已经工作了),但是你还没有真正测试你的应用程序代码。

但要回答你的实际问题:-你必须做一个新的接口IMyOwnCustomMockableQuery<>,与一些转换器或包装类IQuearble<>,然后一个新的linq实现为你的IMyOwnCustomMockableQuery<>,转发所有调用你不想模拟的扩展IQuearble<>。

当然,这将是相当复杂的,需要自己的测试。=)似乎要做很多工作来测试你的模型,而不是测试你的应用程序。我不推荐这种方法。