2011-12-28 75 views
10

如果在Rhino-mocks 3.6中Method1调用1st,然后Method2调用after,然后Method3使用AAA语法,是否可以测试以下示例?我可以在Rhino-Mocks 3.6中使用AAA语法测试方法调用顺序吗?

// Assert 
var mock = MockRepository.GenerateMock<ISomeService>(); 

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

回答

19

下面是做这件事......

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

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

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

总之,测试的实现会导致脆弱的测试。脆弱的测试会导致放弃测试。你不想去那里。

希望这会有所帮助。

+16

这并非总是如此。有秩序问题的有状态对象的合同,你不能总是避免这些合同。 – sanosdole 2012-06-23 16:02:59

+0

我同意@sanosdole的评论,但在我的情况下,你是发现。我应该测试结果...而不是执行。谢谢! – MoMo 2014-03-20 20:07:45

+0

如果代码已经有时间耦合,它也应该被测试。 – SerG 2017-10-03 10:29:00

5

以下是如何很好地做到这一点。

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

找到了答案from this blog.

+0

为了使它在RhinoMocks 3.5中运行,我不得不稍微修改它 - 请参阅下面的答案。 – Clarkeye 2015-06-10 10:36:02

+0

这不是AAA语法。 – SerG 2017-10-03 10:35:55

1

下面介绍如何通过建立断言到每一个方法调用来做到这一点。

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

由于这是在中行为运行断言混淆了正常的安排,行为断言模式,我想包括对这些情况下更容易地识别测试失败非常具体的错误消息。

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<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

的mocks.Ordered()由@craastad指定的语法是做正确的方式,但我无法得到它在RhinoMocks 3.5的工作 - 而不是我不得不调整它没有实例工作MockRepository的是@使用craastad的解决方案调用有序()上:

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

如果你做这种方式,这也似乎是不必要的()或者调用fooMock.Replay。

+3

有人标记了这个答案,这很公平,但如果你打算这么做,那么你至少可以解释为什么! – Clarkeye 2016-04-25 09:44:19

相关问题