0

我正在使用一个模拟(使用 Moq)设置一个测试IQueryable,我想在.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);
}

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

4

1 回答 1

1

MattiasG 暗示了解决方案。您应该提供一个 IQuerable pocos,它将始终生成具有已知结果的查询,从而为您提供您期望的 .Count。

因此,此处代码中未显示的是正确完成的;传递 pocos 的方法也应该被模拟,以提供您可以做出正确断言的数据。

很难找到测试的良好平衡。这真的是一种艺术形式。但是,如果您使用的是最小起订量,则应该关注高阶“工作单元”,而不是单个方法内部发生的事情。

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

但是要回答您的实际问题:-您必须创建一个新接口 IMyOwnCustomMockableQuery<>,其中包含一些转换器或包装类到 IQuearble<>,然后为您的 IMyOwnCustomMockableQuery<> 转发所有呼叫的新 linq 实现不想要模拟 IQuearble<> 上的扩展。

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

于 2013-01-19T11:47:23.260 回答