我可以在Rhino-Mocks 3.6中使用AAA语法测试方法调用顺序吗?

如果Method1在Rhino-mocks 3.6中调用1st,然后调用After后面的Method2,然后使用AAA语法调用Method3,是否可以测试以下示例?

// Assert var mock = MockRepository.GenerateMock(); // Act myObject.Service = mock; // How should I change this part to ensure that Rhino Mocks check the call order as well? mock.AssertWasCalled(m=>m.Method1()); mock.AssertWasCalled(m=>m.Method2()); mock.AssertWasCalled(m=>m.Method3()); 

这是一种方法……

 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()); 

你可以,但你真的不应该。 您应该专注于测试externall可观察行为,而不是实现。

方法调用顺序可以在不影响与API客户端的合同的情况下进行更改。 在这种情况下,即使不应该,您的测试也会失败。

简而言之,测试实施会导致脆弱的测试。 脆弱的测试导致放弃测试。 你不想去那里。

希望这可以帮助。

以下是如何做得很好。

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

从这个博客找到了答案。

这是通过在每个方法调用中构建断言来实现的。

 // Arrange - Build the necessary assertions into the stubbed method invocations. var mock = MockRepository.GenerateMock(); 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()); 

由于这是通过在mid-act中运行断言来混合正常的arrange-act-assert模式,我喜欢为这些实例包含非常具体的错误消息,以便更容易地识别测试失败。

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

您还可以通过在执行步骤期间将每个调用的结果保存在变量中,然后在断言步骤期间检查变量状态来实现类似的结果。 这样可以更好地保留arrange-act-assert模式的划分,但是编写和维护的管道代码更多。

 // Arrange - Build the necessary state variables into the stubbed method invocations. bool wasMethod1Called; bool wasMethod2Called; bool wasMethod2CalledBeforeMethod1; bool wasMethod3CalledBeforeMethod2; var mock = MockRepository.GenerateMock(); 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."); 

@craastad指定的mocks.Ordered()语法是正确的方法,但是我不能让它在RhinoMocks 3.5中运行 – 相反,我必须调整它才能在没有使用@ craastad解决方案的MockRepository实例的情况下工作调用Ordered():

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

如果你这样做,它似乎也没有必要调用fooMock.Replay()。