Can I test method call order with AAA syntax in Rhino-Mocks 3.6?

后端 未结 5 1516
南笙
南笙 2020-12-19 01:19

Is it possible to test for the following example if the Method1 called 1st, then Method2 called after and then Method3 by using the AAA syntax, in Rhino-mocks 3.6 ?

相关标签:
5条回答
  • 2020-12-19 01:40

    The mocks.Ordered() syntax specified by @craastad is the right way to do it, but I couldn't get it to work in RhinoMocks 3.5 - instead I had to tweak it to work without the instance of MockRepository that @craastad's solution used to call Ordered() on:

    var fooMock = MockRepository.GenerateMock<IFoo>();
    using (fooMock.GetMockRepository().Ordered())
    {
        fooMock.Expect(x => x.Method1());
        fooMock.Expect(x => x.Method2());
    }
    
    var bar = new Bar(fooMock);
    bar.DoWork();
    
    fooMock.VerifyAllExpectations();
    

    If you do it this way, it also appears to be unnecessary to call fooMock.Replay() either.

    0 讨论(0)
  • 2020-12-19 01:43

    Here is how to do it nicely.

    var mocks = new MockRepository();
    var fooMock = mocks.DynamicMock<IFoo>();
    using (mocks.Ordered())
    {
        fooMock.Expect(x => x.Method1());
        fooMock.Expect(x => x.Method2());
    }
    fooMock.Replay();
    
    var bar = new Bar(fooMock);
    bar.DoWork();
    
    fooMock.VerifyAllExpectations();
    

    Found the answer from this blog.

    0 讨论(0)
  • 2020-12-19 01:48

    You can, but you really shouldn't. You should focus on testing the externall observable behaviors, rather than the implementation.

    Method call order can change without affecting the contract with the client of the API. In that case, your test will fail, even when it shouldn't.

    In short, testing implementation leads to brittle tests. Brittle tests lead to abandonment of the tests. You don't want to go there.

    Hope this helps.

    0 讨论(0)
  • 2020-12-19 01:48

    Here's how to do it by building assertions into each method invocation.

    // Arrange - Build the necessary assertions into the stubbed method invocations.
    var mock = MockRepository.GenerateMock<ISomeService>();
    mock.Stub(m => m.Method1()).WhenCalled(inv => mock.AssertWasNotCalled(m => m.Method2()));
    mock.Stub(m => m.Method2()).WhenCalled(inv => mock.AssertWasNotCalled(m => m.Method3()));
    
    // Act
    myObject.Service = mock;
    
    // Assert - Ensure each expected method was called.
    mock.AssertWasCalled(m => m.Method1());
    mock.AssertWasCalled(m => m.Method2());
    mock.AssertWasCalled(m => m.Method3());
    

    Since this is mixes up normal arrange-act-assert pattern by running assertions in mid-act, I like to include very specific error messages for these instances to identify test failures more easily.

    mock.Stub(m => m.Method1()).WhenCalled(inv =>
        mock.AssertWasNotCalled(m => m.Method2(), opt =>
            opt.Message("Method2 cannot be called before Method1.")));
    

    You could also achieve a similar result by saving the result of each invocation in a variable during the act step, and then checking the variable states during the assert step. This better preserves the division of the arrange-act-assert pattern, but it is more plumbing code to write and maintain.

    // Arrange - Build the necessary state variables into the stubbed method invocations.
    bool wasMethod1Called;
    bool wasMethod2Called;
    bool wasMethod2CalledBeforeMethod1;
    bool wasMethod3CalledBeforeMethod2;
    
    var mock = MockRepository.GenerateMock<ISomeService>();
    mock.Stub(m => m.Method1()).WhenCalled(inv =>
    {
        wasMethod1Called = true;
    });
    mock.Stub(m => m.Method2()).WhenCalled(inv =>
    {
        wasMethod2Called = true;
        wasMethod2CalledBeforeMethod1 = !wasMethod1Called;
    });
    mock.Stub(m => m.Method3()).WhenCalled(inv =>
    {
        wasMethod3CalledBeforeMethod2 = !wasMethod2Called;
    });
    
    // Act
    myObject.Service = mock;
    
    // Assert - Ensure each expected method was called, and that they were called in the right order.
    mock.AssertWasCalled(m => m.Method1());
    mock.AssertWasCalled(m => m.Method2());
    mock.AssertWasCalled(m => m.Method3());
    Assert.That(wasMethod2CalledBeforeMethod1, Is.False, "Method2 cannot be called before Method1.");
    Assert.That(wasMethod3CalledBeforeMethod2, Is.False, "Method3 cannot be called before Method2.");
    
    0 讨论(0)
  • 2020-12-19 01:55

    Here's one way to do it...

    mock.AssertWasCalled(m=>m.Method1(), options => options.WhenCalled(w => mockService.AssertWasNotCalled(x=>x.Method2())));
    mock.AssertWasCalled(m=>m.Method2(), options => options.WhenCalled(w => mockService.AssertWasNotCalled(x=>x.Method3())));
    mock.AssertWasCalled(m=>m.Method3());
    
    0 讨论(0)
提交回复
热议问题