RhinoMocks VerifyAllExpectations 对存根方法的多个 Expects 失败

RhinoMocks VerifyAllExpectations fails for multiple Expects on stubbed method

亲爱的 RhinoMocks 用户。我是 RhinoMocks 的新手,在思考问题时遇到了问题。我需要在 class 中测试两个方法,其中一个调用另一个多次。我已经分别测试了多次调用的方法,设置有些复杂,所以测试另一种方法的想法是对已经测试过的方法进行存根。这是一个最小的例子:

     public class TestedClass
     {
         public virtual void DoSthOnce(List<int> listParam)
         {
             foreach (var param in listParam)
                DoSthMultipleTimes(param);
         }

         public virtual void DoSthMultipleTimes(int intParam)
         {
             Console.WriteLine("param: " + intParam);
         }
    }

DoSthMultipleTimes() 已经过测试。以下测试代码有效并验证是否为作为参数提供给 DoSthOnce().

的列表的每个元素调用了 DoSthMultipletimes()-Method
    var paramList = Enumerable.Range(1, 10).ToList();
    var mock = MockRepository.GeneratePartialMock<TestedClass>();
    mock.Stub(m => m.DoSthMultipleTimes(Arg<int>.Is.Anything))
        .WhenCalled(mi =>
        {
            // Only for debug; this method is empty in the actual test code.
            Console.WriteLine("Stub called with " + mi.Arguments[0]);
        });

     mock.DoSthOnce(paramList);

     // This will not throw an exception
     foreach (var param in paramList)
         mock.AssertWasCalled(m => m.DoSthMultipleTimes(param));

输出符合预期:

    Stub called with 1
    Stub called with 2
    Stub called with 3
    Stub called with 4
    Stub called with 5
    Stub called with 6
    Stub called with 7
    Stub called with 8
    Stub called with 9
    Stub called with 10

但是,尽管从我的理解来看应该与上面的相同,但下面的代码没有抛出异常:

    var paramList = Enumerable.Range(1, 10).ToList();
    var mock = MockRepository.GeneratePartialMock<TestedClass>();
    mock.Stub(/*same as above*/).WhenCalled(/*same as above*/);
    foreach (var param in paramList)
        mock.Expect(m => m.DoSthMultipleTimes(param));

    mock.DoSthOnce(paramList);
    mock.VerifyAllExpectations();

控制台输出相同,但 VerifyAllExpectations() 抛出 ExpectationViolationException。附加信息是:

    TestedClass.DoSthMultipleTimes(1); Expected #1, Actual #0.
    TestedClass.DoSthMultipleTimes(2); Expected #1, Actual #0.
    ...
    TestedClass.DoSthMultipleTimes(10); Expected #1, Actual #0.

参数是正确的,但是这里到底是什么问题?

我猜是因为你的存根本身。

这段代码将注册您想要的各种期望:

foreach (var param in paramList)
    mock.Expect(m => m.DoSthMultipleTimes(param));

这将设置调用 DoSthMultipleTimes(1)、DoSthMultipleTimes(2) 等的期望值。

但是您的 Mock.Stub 代码会覆盖/存根实现本身。这导致 Rhino 将执行此 override/method(而不是调用原始 class 的原始 DoSthMultipleTimes 方法)。因此,当调用 VerifyAllExpectation 时,调用了原始 class 中方法的 none 。

您可以通过删除以下内容来验证以上内容:

mock.Stub(m => m.DoSthMultipleTimes(Arg<int>.Is.Anything))
    .WhenCalled(mi =>
    {
        // Only for debug; this method is empty in the actual test code.
        Console.WriteLine("Stub called with " + mi.Arguments[0]);
    });

由于您使用的是 PartialMock,如果您没有实现存根,它将调用原始方法。并且按理说,它现在将成功超越所有的期望。

(注意:使用 PartialMock 时要小心,因为如果不被存根(即:数据库调用等),它会 运行 原始方法)。