views:

393

answers:

5

Is it correct that Rhino Mocks stubs and mocks are only good for interfaces, not concrete classes? I spent quite a time trying to make this piece of code working. What I did not expected is that stabbed pubSubClient will always call Send method from the class. That method has some dependencies and throws exception.

[Test]
public void Test01()
{
    PubSubMessage psm = new PubSubMessage(); 
    var pubSubClient = MockRepository.GenerateStub<PubSubClient>();
    pubSubClient.Stub(x => x.Send(psm)).IgnoreArguments().Return(null);
    // actual PubSubClient Send method throws exception
    // the rest of the test is skipped...
}

However, when I have extracted the interface and run the same test with IPubSubClient, it seems to be working as expected.

Does it mean that I have to extract the interface for every class I want to mock/stub with Rhino? Or I am missing something, technically or conceptually?

UPDATE: OK, It seems I figured out what part I was missing: Rhino Mocks cannot intercept calls to non-virtual methods. So, I guess I have either use interfaces or make every method on the concrete class virtual. Please correct me if there's another option.

+2  A: 

Partial mocks allow you to mock out functionality of a concrete class. See: http://www.ayende.com/wiki/Rhino+Mocks+Partial+Mocks.ashx

Bryan Rowe
I'm afraid partial mocks don't quite do that. They are helpful with mocking some unimplemented methods in abstract classes, but if there's implementation, it is still called. In other words, in my example, replacing MockRepository.GenerateStub<PubSubClient>() with MockRepository.GeneratePartialMock<PubSubClient>() doesn't change anything.
Dmitry Duginov
make your method virtual.
Bryan Rowe
+2  A: 

You have to make the methods virtual. Rhino mocks (and most other isolation frameworks) utilizes proxy classes in order to create the stubs/mocks.

If you use TypeMock Isolator you can mock anything because this isolation framework utilizes the .NET Profiler API in order to create its' stubs/mocks

Jon Erickson
+1. As the OP mentioned in his update, the methods have to be virtual. This is true of Moq as well, and (I believe) every .NET isolation framework except TypeMock Isolator. The cheap and easy fix is to make the methods virtual (or extract an interface).
TrueWill
A: 

I don't think there's another way of doing this other than making any methods you want to mock virtual - I believe the way mocks of concrete classes are created is by dynamically sub-classing the concrete class being mocked and then overriding the given methods with the behaviour you specify in the test, so this requires a virtual method to work correctly.

Lee
+6  A: 

Bryan's answer of using partial mocks is incorrect. That's not what partial mocks are for.

Jon Erickson's answer is mostly correct: Rhino Mocks and Moq can't intercept non-virtual calls, nor can they intercept static methods or properties. That means you can't fake the following:

DateTime.Now; // static property, can't fake static property
someClass.SomeNonVirtualMethod(); // can't fake non-virtual method
sealedClass.Foo(); // can't fake anything on sealed classes
Utilities.SomeStaticMethod(); // can't fake static methods
someList.Any(); // can't fake extension methods like Linq's .Any()

TypeMock can fake these, as Jon mentioned.

It should be noted there is an additional mocking framework that can intercept all calls: the Microsoft Moles framework. It works the same way TypeMock does, it uses the .NET profiler API to intercept calls.

Moles is free (for now). It's also beta. Moles only only works with Microsoft Pex tools. And its API is clearly inferior to TypeMock's refined, elegant API.

Judah Himango
If you state that partial mocks are not for something it is more helpful to say what they ARE for in your response. Partial mocks are intended to mock only Part of a class, this makes them handy (and required) to mock out an Abstract class where a normal mock cannot handle this. This allows the testing of abstract methods. A partial mock (at least in Rhino) will mock any class and is not restricted to Abstract classes, be aware however if there is implementation code that will be called on return.
krystan honour
A: 

That's essentially correct, and is generally good practice. However, it's only really useful for a specific type of coding.

Don't think of objects as things that some 'higher power' can manipulate. Instead, think of them as autonomous 'people' that can send messages to each other. An interface represents the messages sent by a single object.

You then use mocks to verify that the correct messages were sent, not to provide fake implementations of dependencies.

Ideally, you don't create an interface that exactly matches an existing class - instead, the class consuming the interface declares its needs in the form of an interface.

kyoryu