Moq是一种自我回归的智慧

时间:2013-01-18 07:52:58

标签: c# testing mocking moq iqueryable

我正在使用模拟的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了,所以我实际上并不需要担心Pocopocos的内容。但是,我希望能够控制recentPocos.Count的价值,并且我希望能够知道无论在pocos上运行多少查询,它都会返回相同的值在访问.Count之前。

1 个答案:

答案 0 :(得分:1)

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

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

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

换句话说。假设你设法让Count始终返回5.然后你有一个测试检查你的依赖方法中Count是否为5。它是。你做了什么?好吧,你可以声明Count将返回一个int(我们知道这已经有效了),但你还没有真正测试过你的应用程序代码。

但要回答你的实际问题: - 您必须创建一个新接口IMyOwnCustomMockableQuery&lt;&gt;,使用一些转换器或包装器类到IQuearble&lt;&gt;然后为你的IMyOwnCustomMockableQuery&lt;&gt;创建一个新的linq实现将你不想嘲笑的所有电话转发给IQuearble&lt;&gt;上的表决。

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