【问题标题】:Moq unit test with It.IsAny<DateTime>() fails使用 It.IsAny<DateTime>() 的 Moq 单元测试失败
【发布时间】:2011-07-24 13:11:30
【问题描述】:

我正在使用 Moq 为项目编写单元测试,当我尝试验证 DateTime 属性是否已分配值时,其中一个测试失败。这是我的验证(失败):

        _mockTaskContext.Verify(context => context.TaskQueue.AddObject(It.Is<TaskQueueItem>(
            task_queue => task_queue.TaskCode == (int)TaskCode.MyTask
                    && task_queue.ClientID == ExpectedClientID
                    && task_queue.JobNumber == It.IsAny<int>()
                    && task_queue.Requester == String.Empty
                    && task_queue.JobStatus == (int)JobStatus.Submitted
                    && task_queue.TimeQueued == It.IsAny<DateTime>()
                    && task_queue.TimeStarted == new DateTime(1900, 1, 1)
                    && task_queue.TimeStopped == new DateTime(1900, 1, 1)
                    && task_queue.TaskParameters == expectedTaskParam
            )), Times.Once());

如果我在task_queue.TimeQueued 上注释掉预期,那么测试通过,而无需对我的测试进行任何其他更改。另外,如果我将TimeStartedTimeStopped 的要求从new DateTime(1900, 1, 1) 更改为It.IsAny&lt;DateTime&gt;(),测试将失败。我已经使用实际实现而不是模拟存储库在单元测试之外运行了被测代码,并且 TimeQueued 被正确分配了它的值。知道为什么 It.IsAny 似乎无法对 DateTime 属性正常工作,还是我的期望设置不正确?

更新:我在其他测试中使用 It.IsAny() 没有任何问题,但这个测试仍然失败。我认为这可能是因为它在 It.Is lambda 表达式中,但我不知道如何解决这个问题。

【问题讨论】:

    标签: c# moq


    【解决方案1】:

    我确信It.IsAny&lt;&gt;() 语法必须在模拟对象的范围内使用。在这种情况下,当您直接使用 Setup 和模拟参数时。这是因为模拟对象处于记录模式,捕获您传递给参数的值,所以

    mock.Setup(x => x.Foo(It.IsAny<Bar>()));
    

    将在执行 Setup 行时处理参数。

    但是,在您的示例中,您尝试在委托中使用 It.IsAny&lt;&gt;() 来验证传入的参数是否匹配。当这种情况发生时,mock 不是在记录,而是在作为被测对象的结果被使用的过程中(这要晚得多)。

    所以someValue == It.IsAny&lt;DateTime&gt;() 不能评估为真,因为IsAny 方法的返回必须返回一个匹配的值才能使其为真。我希望It.IsAny&lt;int&gt;() 也不起作用。

    我的建议是您必须匹配确切的值,或者在这种情况下匹配一个日期范围

    && IsInRange(DateTime.MinValue, DateTime.MaxValue, task_queue.TimeQueued)
    

    IsInRange 只是另一种检查值的方法,它介于 2 min 和 max bounds 之间。

    【讨论】:

    • 我想你可能误读了我的代码,我没有使用回调。实际上,自从我发布了这个,我已经重组了我的测试并且不再进行设置,除非我需要返回一些东西,它现在严格使用验证(...),所以我会更新我的问题。 It.IsAny() 确实可以正常工作,但是如果我尝试将 String.Empty 替换为 It.IsAny() 它会失败。
    • It.Is&lt;TaskQueueItem&gt; 中使用的委托不是在调用模拟上的设置时而是在被测代码运行时调用的。我想说的是,使用It.IsAny&lt;&gt; 只能在调用安装程序时使用,而不是稍后。我做了一个小测试,使用It.IsAny&lt;int&gt;() 确实失败了。在这种情况下,您的 int 值可能是 0。
    • 你是对的!针对 It.IsAny() 检查的 int 值已在数据库中分配,因此在我的测试中为 0。你提到的回调让我走上了正确的轨道,我意识到我真正想要的可能是 2 个单元测试,1 个检查 Add 和 SaveChanges() 方法是否被调用(行为验证)和一个单独的单元测试来验证值被分配的是正确的(状态验证)。感谢您让我走上正确的道路!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-04-12
    • 1970-01-01
    • 1970-01-01
    • 2018-06-06
    • 1970-01-01
    • 2011-12-24
    • 2015-10-04
    相关资源
    最近更新 更多