Rhino Mocks Challenge: Implement This Feature
Okay, let us see if this approach works...
Here is a description of a feature that I would like to have in Rhino Mocks (modeled after a new feature in Type Mock). I don't consider this a complicated feature, and I would like to get more involvement from the community in building Rhino Mocks (see the list of all the people that helped get Rhino Mocks 3.5 out the door).
The feature is fluent mocks. The idea is that this code should work:
var mockService = MockRespository.GenerateMock<IMyService>();
Expect.Call( mockService.Identity.Name ).Return("foo");Assert.AreEqual("foo", mockService.Identity.Name);
Where identity is an interface.
The best place to capture such semantics is in the RecordMockState.
Have fun, and send me the patch :-)
Comments
Is this really something you __want in Rhino.Mocks?
I know what you're getting at, and I realize that TypeMock has it... but recursive mocks like this don't cause you to feel the pain of the Demeter violation in the code under test. What happened to the idea (or was it just an ideal) of reinforcing good practices by making it painful to... well... not such good things - like breaking LoD?
I'm just curious why you've decided on this particular feature? (and its OK if your answer was just that you threw a dart at the dartboard to pick one.) :)
I find it interesting that calls to action have so few responses while the philsophical debates over buses and what not have so many... I'll wait a few days and if no one answers then I'll take a crack at it.
What is Identity.Name? Can you provide a sample interface implementation to go with this? I'm unsure if this is a method call or what exactly .Identity is.
Er, guess I should have re-read it a few times, this?
public interface ISomeInterace {
}
public interface IMyService {
}
<imyservice();
This is way too subtle for me :S Why should interfaces in a mock have different semantics from strings and ints?
I could understand if I asked specifically for a MockRespository.GenerateDeepMock <imyservice(); and it was documented that this would mock all non-sealed classes that was not set.
I think I'm with Steven on this one. Historically, we've had Type Mock over on the most-effective-for-legacy-code side of the fence and everyone else over on the more-strongly-encouraging-good-practices side of the fence and a feature like this seems at first like a step towards, if not down, a slippery-slope.
This thread already tackled it: groups.google.com/.../89c8e41fdd5771cb?hl=en
Do you want a feature such an Isolator's recursive mocking?
In response to Steve, Jeremy, et. al., the utility of this feature is in the ability to mock fluent interfaces. The Law of Demeter goes out the window when people are using fluent interfaces; we expect the client to make deep calls.
"I would like to get more involvement from the community in building Rhino Mocks "
No, you are just getting lazy. I am not your helpdesk. :P
@Ryan - True enough. The point once missed is now taken and mine conceded. :)
Simon, don't you think the test code in that thread is much more verbose and more difficult to read than what is asked for here?
I just pointed out that it was already discussed, and solved something more complex than the scenario proposed here, which it solves as well. If you want code trivial to read, you should stay away from RhinoMocks.
So you just want the Record / Replay switch to occur implicitly where actions inside of Expect should be performed in record mode and actions outside of it should not?
The delegate-based syntax is easy of course:
Expect.Call(() => Foo.DoSomething()).Return("Blah");
The Call method can just enter record mode, evaluate the delegate (or disassemble the lambda expression) and return to replay mode.
But if you really want:
Expect.Call(Foo.DoSomething()).Return("Blah");
Then we have to find another way to run code before the mocked expression to enter record mode.
Here's one possible hack:
public static class Expect
{
<object Call
}
So the "Call" method can be represented as a property that returns a delegate with a side-effect of doing something before the call runs.
Ugh. A property with a side-effect. Maybe we're thinking about this wrong. Let's try something else.
Consider the behavior of a stubbed method. (Without loss of generality, properties, events can follow the same logic.)
Initially the stubbed method should have no real behavior. When you call it, it should do nothing and just return default values to the caller. So that means that as long as we have not assigned any behavior to the stubbed method, calling it ought to be completely harmless.
If we've already set behaviors for a stubbed method (like throwing an exception), then we usually will not try to set additional behaviors. I know Rhino.Mocks allows the user to record multiple ordered or unordered expectations, but we could actually live without that feature...
So consider this code:
Expect.Call(Foo.DoSomething()).Return("bar");
Assert.AreEqual("bar", Foo.DoSomething());
Here's one way to make the fluent syntax work given the C# order of evaluation:
Foo.DoSomething() gets evaluated. Well, it's just a stubbed method so it does nothing of its own, but it does remember that it was called.
The surrounding fluent expression involving Expect.Call(...) or LastCall gets evaluated. It knows that the previously evaluated stubbed method was Foo.DoSomething(). So it sets its behavior.
Foo.DoSomething() runs again. This time we have some behavior associated with it, which we perform for real.
Oops, I think I missed the point. You're actually talking about implementing recursive mocks, not fussing over the syntax.
Ahh well.
Jeff,
The property that return a delegate with a side effect is evil, but exactly what I need in this scenario, thanks
Comment preview