Ayende @ Rahien

It's a girl

Rhino Mocks Futures

I have been thinking about this for a while now, and I am getting ready to release Rhino Mocks 3.5. The major feature is taking advantage on C# 3.0 language features. This allow some really interesting experimentation.

var mockedSmsSender = mocks.ToBeNamedMocked<ISmsSender>();
var mockedRepository = mocks.ToBeNamedMocked<IUserRepository>();
mockedRepository.Stub( x=> x.GetUserByName("ayende") ).Return( new User{Name="ayende", Pass="1234"});

new LoginController(mockedSmsSender, mockedRepository ).ForgotYourPassword("ayende");

mockedSmsSender.Verify( x => x.Send("ayende, your pass is 1234");

A few things to note about this code.

  • No explicit record / replay model
  • Arrange Act Assert model
  • You can setup return values by using Stub()
  • You can setup expectations using Expect(), with the same syntax
  • More complex verification is also possible.
  • I don't know what to call this new mode

As an aside, I am deprecating CreateMock in favor of StrictMock. Using strict mocks by default was a bad design decision on my part.

Thoughts?

Comments

Stuart C
04/20/2008 04:03 PM by
Stuart C

I really like the Arrange Act Assert model, the syntax is great too. Why .ToBeNamedMocked<> as oposed to just .ToBeMocked<>? Seems strange, too many verbs...

Ayende Rahien
04/20/2008 04:17 PM by
Ayende Rahien

Stuart,

That is a temporary name because I don't know what to call this.

Graham
04/20/2008 04:24 PM by
Graham

I think the rename from CreateMock to StrictMock is a good idea. I use DynamicMock regularly and this makes the difference more explicit.

I also like the idea of being able to create stubs on the fly. Sometimes a stub is all you need and it is convenient for it to be in the same framework as the mocking.

I look forward to this new version (as soon as Resharper supports .NET 3.0).

Andrew Davey
04/20/2008 04:55 PM by
Andrew Davey

I really like the idea of verifying what I expected to happen after I have invoked my SUT. It's much nicer than the currently divided Expect and Verify.

I like to read tests as: Do X with SUT, assuming it did the following, assert these facts.

Stuart C
04/20/2008 06:15 PM by
Stuart C

Ahhh, I get it. Now it makes sense. :)

Andrey Shchekin
04/20/2008 07:10 PM by
Andrey Shchekin

I am really interested how would you solve the expectations that do not care about some of the arguments. I have done a similar thing for NMock2,

Expect.Once.That(() => mock.GetUserByName("ayende")).WillReturn(new User{Name="ayende", Pass="1234"});

but this obviously do not allow any matchers for "ayende" except for the default (equality? sameness?) matcher.

I was thinking about

Expect.Once.That(() => mock.GetUserByName(Any.String.StartingWith("ayende"))).WillReturn(new User{Name="ayende", Pass="1234"});

This would be parseable and compile if Any.String.StartingWith() (and Any.String if you do not care) were convertible to string. But I never got to implement this.

So I am looking forward how you solve that -- which would probably make me abandon NMock2 (for now, I like expect-that-willreturn more than stub-return, since it is a more natural language).

Ayende Rahien
04/20/2008 08:02 PM by
Ayende Rahien

mockedSernder.Verify( x => x.Send( Arg.Matching( s => s.StartsWtih("a") )

Oran
04/20/2008 09:02 PM by
Oran

If I'm picturing this correctly, I'm thinking of the new mode as "modeless/stateless stub mode" where you can opt into stricter behavior verification and possibly opt into the record-replay model as well.

How about CreateStub, StubMock, ModelessMock, or StatelessMock? Or perhaps an overload of CreateMock or DynamicMock with a config enum, or a new method simply named Mock that takes a config enum for returning all of the various mock types. It would also be nice to have the option of turning on property behavior if it's not on by default.

Thomas Eyde
04/20/2008 10:45 PM by
Thomas Eyde

This looks similar to Moq. However, I have only seen blog posts about Moq, never tried it myself. But it looks cool. When there are several, but similar frameworks available, it would be nice to know why or when Rhino Mock would be the better choice. In other words, I'd like some marketing, please.

Krzysztof Koźmic
04/21/2008 05:00 AM by
Krzysztof Koźmic

I'd recommend moving ALL mock creation methods to one method, and just pass parameters to it. It makes API cleaner, and easier to use.

public T CreateMock(params object[] argumentsForConstructor);

public object CreateMock(Type type, params object[] argumentsForConstructor);

public T CreateMockWithRemoting(params object[] argumentsForConstructor);

public object CreateMockWithRemoting(Type type, params object[] argumentsForConstructor);

public T CreateMultiMock(params Type[] extraTypes);

public object CreateMultiMock(Type mainType, params Type[] extraTypes);

public T CreateMultiMock(Type[] extraTypes, params object[] argumentsForConstructor);

public object CreateMultiMock(Type mainType, Type[] extraTypes, params object[] argumentsForConstructor);

public T DynamicMock(params object[] argumentsForConstructor);

public object DynamicMock(Type type, params object[] argumentsForConstructor);

public T DynamicMockWithRemoting(params object[] argumentsForConstructor);

public object DynamicMockWithRemoting(Type type, params object[] argumentsForConstructor);

public T DynamicMultiMock(params Type[] extraTypes);

public object DynamicMultiMock(Type mainType, params Type[] extraTypes);

public T DynamicMultiMock(Type[] extraTypes, params object[] argumentsForConstructor);

public object DynamicMultiMock(Type mainType, Type[] extraTypes, params object[] argumentsForConstructor);

public static T GenerateStub(params object[] argumentsForConstructor);

public static object GenerateStub(Type type, params object[] argumentsForConstructor);

public T PartialMock(params object[] argumentsForConstructor) where T: class;

public object PartialMock(Type type, params object[] argumentsForConstructor);

public T PartialMultiMock(params Type[] extraTypes);

public T PartialMultiMock(Type[] extraTypes, params object[] argumentsForConstructor);

public object PartialMultiMock(Type type, params Type[] extraTypes);

public object PartialMultiMock(Type type, Type[] extraTypes, params object[] argumentsForConstructor);

public T Stub(params object[] argumentsForConstructor);

public object Stub(Type type, params object[] argumentsForConstructor);

Right now those are all methods that create some kind of mock. (v3.4). I guess that having one or two methods like

public TType Mock();

public TType Mock(MockKind kind);

public TType Mock(MockKind kind, params Type[] extraTypes);

public TType Mock(MockKind kind, params object[] ctorArgs);

public TType Mock(MockKind kind, Type[] extraTypes, params object[] ctorArgs);

Would make it cleaner, less scary for newcomers and easier to strart with.

Benny Thomas
04/21/2008 07:13 AM by
Benny Thomas

I agree with Krzysztof.

You should have seperated Remoting, Multi, Dynamic, Partial to its own Classes and let them each implement their own:

public TType Mock();

public TType Mock(MockKind kind);

public TType Mock(MockKind kind, params Type[] extraTypes);

public TType Mock(MockKind kind, params object[] ctorArgs);

public TType Mock(MockKind kind, Type[] extraTypes, params object[] ctorArgs);

Krzysztof Koźmic
04/21/2008 04:06 PM by
Krzysztof Koźmic

@Benny

I actually had something else in mind.

Take a look at this: http://kozmic.pl/archive/2008/04/21/simplifying-rhino.mocks.aspx

Ben Scheirman
04/21/2008 05:13 PM by
Ben Scheirman

I was thinking about this exact implementation during the mocking session at alt.net.

I like it, however one area that will suffer is if you have a failed expectation you cannot know to throw an exception.

Other than that, it's a good feel.

(oh and -1 for the name, I think we can do better)

I don't fully agree with mocks.Mock(MockType.Scrict) .... that doesn't read well.

Alex Simkin
04/21/2008 06:36 PM by
Alex Simkin

@Ayende

"I am deprecating CreateMock in favor of StrictMock"

then you should deprecate DynamicMock in favor of RelaxedMock or even NonStrictMock

Krzysztof Koźmic
04/21/2008 07:08 PM by
Krzysztof Koźmic

@Ben

How would you call it then? Oh, and version on my blog has changed MockKind to be just shorter: Kind, so you'd have

var foo = repo.Mock(Kind.Strict);

And as for the method name

Its supposed to create mocks so I think this name suits the purpose.

"Mock (as verb) IFoo for me please, as for the details I want it to be Strict with no additional parameters".

Ulu
04/21/2008 07:15 PM by
Ulu

Will the new model be totally unusable in VB?

It has lambdas as well, but not those that return void ;(

ulu

Ayende Rahien
04/21/2008 08:01 PM by
Ayende Rahien

The current syntax will still work, so you wouldn't run into any issues

Benny Thomas
04/21/2008 10:04 PM by
Benny Thomas

@Krzysztof

I have a long way to go and did answer kind of fast without looking @ the code and understanding what was going on.

I like your solution, simple and good. But I dont like to pass the kind as a parameter. But I confess that I dont know much about mocking and are @ an early point in learning when to use it. Do one mix all kinds of mocks in a test? Or do one tend to only use one kind of mock when testing?

I would prefer: (I have removed the redudant kind parameter)

public TType Mock();

public TType Mock(params Type[] extraTypes);

public TType Mock(params object[] ctorArgs);

public TType Mock(Type[] extraTypes, params object[] ctorArgs);

But I understand that if you mix several different kinds of mocks in one fixture, this is not an optimal solution.

So your solution seems very elegant.

@Ayende:

I see you are worried that you break your api. But I would say that you only use one mocking version in a project. So if the next version breaks the api, i would first use it in the next project and don't worry that the old api is broken. This is only for test and not for "production".

Benny

Morten Lyhr
04/22/2008 07:08 PM by
Morten Lyhr

Maybe its just me, but I dont understand why I have to declare the mock kind up front?

Usually I have a single Init() method that creates all dependencies as DynamicMock(). And then I have a FactoryMethod that creates the SUT.

Then if I have a test that needs another mock kind I override the instance and call the factory method again.

Something like:

public class LoginPresenterFixture

{

private MockRepository _mockRepository;

private LoginPresenter _loginPresenter;

private LoginView _loginView;


[SetUp]

public void Init()

{

    _mockRepository = new MockRepository();

    _loginView = _mockRepository.DynamicMock<LoginView>();

    CreateLoginPresenter();

}


private void CreateLoginPresenter()

{

    _loginPresenter = new LoginPresenter(_loginView);

}


[Test]

public void Dynamic_Test_Usually_The_Way_To_Go()

{

    using (_mockRepository.Record())

    {

        Expect.Call(_loginView.ShowView);

    }

    using (_mockRepository.Playback())

    {

        _loginPresenter.Show();

    }

}


[Test]

public void Strict_Test_Not_As_Often_Used()

{

    //Override default mock kind

    _loginView = _mockRepository.CreateMock<LoginView>();

    CreateLoginPresenter();


    using (_mockRepository.Record())

    {

        Expect.Call(_loginView.ShowView);

    }

    using (_mockRepository.Playback())

    {

        _loginPresenter.Show();

    }

}

}

Know as far as I am concerned I only need 1 mock creation method. (DynamicMock).

What I really need is the ability to change the kind in each test.

Something like:

public class LoginPresenterFixture

{

private MockRepository _mockRepository;

private LoginPresenter _loginPresenter;

private LoginView _loginView;


[SetUp]

public void Init()

{

    _mockRepository = new MockRepository();

    _loginView = _mockRepository.DynamicMock<LoginView>();

    _loginPresenter = new LoginPresenter(_loginView);

}


[Test]

public void Dynamic_Test_Usually_The_Way_To_Go()

{

    using (_mockRepository.Record())

    {

        Expect.Call(_loginView.ShowView);

    }

    using (_mockRepository.Playback())

    {

        _loginPresenter.Show();

    }

}


[Test]

public void Strict_Test_Not_As_Often_Used()

{

    //Override default mock kind

    _mockRepository.StrictMockBehaviour(_loginView);

    using (_mockRepository.Record())

    {

        Expect.Call(_loginView.ShowView);

    }

    using (_mockRepository.Playback())

    {

        _loginPresenter.Show();

    }

}

}

Ayende Rahien
04/22/2008 07:31 PM by
Ayende Rahien

There is not technical reason not to do that.

I think it would be confusing, though

Morten Lyhr
04/22/2008 08:21 PM by
Morten Lyhr

Confusing?

This way you can read what mock kind it is in the test, you dont have to scroll to the init method to figure out the kind.

Daniel Cazzulino
04/23/2008 02:56 PM by
Daniel Cazzulino

It's good to see MoQ (http://mockframeworks.com/moq) ideas implemented in Rhino. I believe this is the right thing to do, as it lowers the barrier of entry for people getting into unit testing and mocking.

I'm glad that we're finally getting past the "... the record, replay, verify model stands at the core of mocking." (http://ayende.com/Blog/archive/2007/12/26/The-RecordReplayVerify-model.aspx) and we start thinking about what real users find easier to use.

The future is looking good for mocking!

:)

Krzysztof Koźmic
04/23/2008 03:34 PM by
Krzysztof Koźmic

@Morten

I like your idea, though not your implementation.

It'd be easier to implement but I find the idea of 'overriding' the actual mock object not very intuitive.

What do you think about doing things in similar way to the following:

On the surface having just one kind of mock: DynamicMock

You'd write your tests in a usual way, and having additional helper methods to change the mock behaviour for that particular test:

  • Expect.For(_loginView).NothingElse(); //- this would set your mock in a strict mode (as if it was created with _repo.CreateMock();

  • Expect.For(_loginView).AnythingElse();//- this would create a stub

  • Expect.For(_loginView).AnythingForwardCalls(); // I dont like the name, but something like this for partial mocks.

Anyway, the main idea is not to change the mock type, but mock behaviour, as this is what actually matters.

However I'm not sure how deep changes would be required to implement this.

Comments have been closed on this topic.