views:

739

answers:

4

Is there a way with Rhino Mocks to set a property of a Stub if a method is called.

Something like this: (Fake Code in bold)

callMonitor.Expect(x=>x.HangUp()).SetProperty(callMonitor.InACall = false);

The HangUp method returns void and I can't really change that. But I want my stub to know that the call was hung up when HangUp is called.

A: 

There might be some conditions under which you would need to do this, but generally I would expect that you would simply instrument your mock/stub so that it returns the proper values in response to your code. The only exceptions to this that I can think of are partial mocks where you are testing one part of a class and want to mock the other parts.

Setting a mock on a property is pretty easy.

callMonitor.Expect( x => x.HangUp() );
callMonitor.Expect( x => x.InACall ).Return( false );

If callMonitor is a stub, then you can set the property directly.

callMonitor.Stub( x => x.HangUp() );
callMonitor.InACall = false;
tvanfosson
+1  A: 

Yes, you can use the Callback method:

 callMonitor.Expect(x => x.HangUp()).Callback(() => callMonitor.InCall = false);
Mark Seemann
Exactly what I would have written (had I come across this question 6 minutes ago ;)
Richard Szalay
Horrible abuse of the callback mechanism. It's hard to tell, since there's not a lot of info in the post, but I think the OP is not being focused enough in the tests. Read Ayende's cautions on using callbacks at http://ayende.com/Wiki/(S(zwkmge45vdgkgvznp13mgc55))/Rhino+Mocks+Callbacks.ashx
tvanfosson
FWIW -- the callback is supposed to be used to evaluate whether or not the expectation was met, not to do arbitrary computation.
tvanfosson
A: 

I'm no RhinoMocks expert, but I believe this should work.

SetupResult.For(callMonitor.InACall).Return(false);
Stephan
I believe that that was not what he asked about. He asked if there is a way to give the HangUp method an impromptu implementation that sets the InCall property to false when the HangUp method is called. What you have there will cause the InACall method to return false no matter if the HangUp method was called or not.
Mark Seemann
+4  A: 

You can use the "WhenCalled" method to run your own code when a stub is called; pretty sure it should work with Mocks, too. According to the documentation, WhenCalled is a replacement/upgrade for Callback.

callMonitor.Expect(x => x.HangUp())
.WhenCalled(invocation => callMonitor.InCall = false);

Some info at the end of this post: http://grahamnash.blogspot.com/2008/10/rhino-mocks-35.html

Mark Simpson
Still an abuse, even though the method name has changed. WhenCalled, like Callback, is intended to be used in advanced expectation evaluation, not to do arbitrary computation.
tvanfosson
What would you recommend instead? A hand rolled test double?
Mark Simpson
Actually, I'd like to see the test. It seems to me if the test is focused enough, there may not be a need for it.
tvanfosson
To see the test see this question: http://stackoverflow.com/questions/1349324/unit-testing-with-computer-owned-states If there is a "Right way" then I would like to know it.
Vaccano
tvanfosson: I've used it in a few cases to set local variables in tests, though generally not for setting properties on a mock/stub as in this case. It's not caused me any problems as of yet, but I'd like to understand why this is considered an abuse? Is there some form of canonical documentation for Rhino Mocks that says "thou shalt not abuse WhenCalled"? (serious question! I find the Rhino Mocks documentation to be a bit fast and loose + scattered all over the place). Cheers.
Mark Simpson
I agree with Mark. If this is bad then I would like to know why. For my test to work I need to simulate the device hanging up a call. This requires something to happen when the HangUp() method is called. If there is a better way to do this then I want to know it so I can do this right.
Vaccano