【问题标题】:Moq an IQueryable that returns itselfMoq 一个返回自身的 IQueryable
【发布时间】:2013-01-18 07:52:57
【问题描述】:

我正在使用模拟的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>())

我怎样才能让它工作?


编辑:作为对 cme​​ts 的回应,这就是我想像这样使用 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 在pocos 中是什么。但是,我希望能够控制 recentPocos.Count 的值是什么,并且我希望能够知道无论在 .Count 之前运行了多少个查询,它都会返回相同的值 pocos被访问。

【问题讨论】:

  • 看起来您不想模拟 IQueryable 而是模拟 LINQ 查询。
  • 这是什么意思? (我不知道 LINQ 是如何在幕后工作的。)
  • 我不确定您如何使用 Moq 模拟 LINQ 查询。我只是提醒,您想模拟函数Where,这是 LINQ 提供的扩展方法,而不是 IQueryable 的一部分。
  • 我觉得你玩得太过火了。您应该将您的模拟策略定位到高阶服务,并具有替换整个子系统的能力。您似乎在做的是试图在 Linq 上部分模拟单个接口方法,这甚至不是一个实现。我看不到这样做的好处。你想达到什么目的?
  • @Michael Viktor Starberg:我更新了我的问题以回应您的评论。

标签: c# testing mocking moq iqueryable


【解决方案1】:

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

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

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

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

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

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

【讨论】:

    猜你喜欢
    • 2011-05-27
    • 2010-12-12
    • 1970-01-01
    • 1970-01-01
    • 2010-10-17
    • 2019-12-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多