Mock Non-Virtual Interface Implementation

170 views
Skip to first unread message

Kenneth

unread,
Apr 18, 2009, 5:22:50 PM4/18/09
to Rhino.Mocks
Hello,

I got stuck trying to mock the non-virtual implementation of interface
method. Here is a fiction code:
public interface IDoNotOwn {
int DirtyWork(int x);
int Outer(int y);
}

public class DoNotOwn : IDoNotOwn {
public int DirtyWork(int x) {
// do something that hard for unit test to setup.
throw new Exception("Don't call me in unit test");
}

public int Outer(int y) {
return DirtyWork(y + y);
}
}

public class MyClass : DoNotOwn, IDoNotOwn {
public new int Outer(int y) {
return ((IDoNotOwn)this).DirtyWork(y*y);
}
}

[TestFixture] public class MyClassTest {
[Test] public void UsingRhinoMocks() {
const int workResult = 293848;
MockRepository mockery = new MockRepository();
IDoNotOwn o = mockery.CreateMock<MyClass>();
Expect.Call(o.DirtyWork(4)).Return(workResult);
mockery.ReplayAll();
Assert.That(o.Outer(2), Is.EqualTo(workResult));
mockery.VerifyAll();
}
}

That doesn't work. It didn't generate the mock method and call right
into the real DirtyWork. I have also tried MultiMock with interface
and etc. Couldn't get it to work. For more detail, you can see it at
http://kennethxu.blogspot.com/2009/04/rhino-mocks-strikes-to-mock-non-virtual.html

And I have a real word test case that now I wrote my own stub class:
The test case:
http://code.google.com/p/kennethxublogsource/source/browse/trunk/SpringExtension/test/Spring.Data.Extension.Tests/Data/Generic/OracleOdpTemplateTest.cs

And the code to be tested:
http://code.google.com/p/kennethxublogsource/source/browse/trunk/SpringExtension/src/Spring.Data.Extension/Data/Generic/OracleOdpTemplate.cs

Thanks,
Kenneth

Tim Barcz

unread,
Apr 18, 2009, 6:35:46 PM4/18/09
to Rhino...@googlegroups.com
I believe if it's not virtual you're in trouble.

Can you try adapting your code with the adapter pattern (see what I did there? :-)) and then you can mock...

Tim

Tim Barcz

unread,
Apr 18, 2009, 6:36:17 PM4/18/09
to Rhino...@googlegroups.com
Also, you typically do not want to mock an interface you don't own...so again, write an adapater, which you do own, and mock that sucker.

On Sat, Apr 18, 2009 at 4:22 PM, Kenneth <kenn...@gmail.com> wrote:

Kenneth

unread,
Apr 18, 2009, 7:33:12 PM4/18/09
to Rhino.Mocks
Thanks Tim. That's exactly what I mean. It is the non-virtual method.
I don't know if you get a chance to look at my real world code. My
class is inheriting from Spring.Net's AdoTemplate, which has over 100
of overloaded methods that I need to adapter. And further I need to
write over 100 test cases for those adapting methods.

I often rewrite my code when I found it becomes difficult to test and
the result was mostly a better design. But not this time. I was able
to write a Stub my self to complete the test, you can see the solution
using my own Stub instead of Rhino Mocks.

The solution for the fiction code using my own Stub is provided in my
blog post, let me include it here and I believe Rhino Mocks should (if
not now, theoretically can in future :)) be able to do the same. See
the MyClassStub and the test below.

[Test] public void UsingMyStub() {
const int workResult = 293848;
MyClassStub stub = new MyClassStub();
IDoNotOwn o = stub.ExpectCallDirtyWork(4).WillReturn
(workResult);
Assert.That(o.Outer(2), Is.EqualTo(workResult));
stub.VerifyAll();
}

private class MyClassStub : MyClass, IDoNotOwn {
private int _expectedI, _returnValue;
private bool _isCalled;
internal MyClassStub ExpectCallDirtyWork(int i) {
_expectedI = i; return this;
}

internal MyClassStub WillReturn(int value) {
_returnValue = value; return this;
}

internal void VerifyAll() {
Assert.IsTrue(_isCalled, "Call to DirtyWork was not
made.");
}

public new int DirtyWork(int i) {
Assert.That(i, Is.EqualTo(_expectedI));
Assert.IsFalse(_isCalled, "Duplicated call to
DirtyWork.");
_isCalled = true;
return _returnValue;
}
}

Kenneth

On Apr 18, 6:35 pm, Tim Barcz <timba...@gmail.com> wrote:
> I believe if it's not virtual you're in trouble.
>
> Can you try adapting your code with the adapter pattern (see what I did
> there? :-)) and then you can mock...
>
> Tim
>
> >http://kennethxu.blogspot.com/2009/04/rhino-mocks-strikes-to-mock-non...
>
> > And I have a real word test case that now I wrote my own stub class:
> > The test case:
>
> >http://code.google.com/p/kennethxublogsource/source/browse/trunk/Spri...
>
> > And the code to be tested:
>
> >http://code.google.com/p/kennethxublogsource/source/browse/trunk/Spri...
>
> > Thanks,
> > Kenneth

Kenneth

unread,
Apr 19, 2009, 9:04:06 AM4/19/09
to Rhino.Mocks
Tim,

Given another thought, I found a variation of adapter approach. With
the help of an internal variable, I was able to test using RhinoMocks
(see code below). But I still wish I can directly Mock the interface
methods regardless of the virtual declaration of the implementation. I
know Spring.Net proxy is able to do this, never used Castle so I
cannot say for that. Maybe I'll take a look at the RhinoMocks souce
code when I have some time to spend. :) Thanks again!

Cheers,
Kenneth

public class MyClass : DoNotOwn, IDoNotOwn {
internal IDoNotOwn self;

public MyClass() {
self = this;
}

public new int Outer(int y) {
return self.DirtyWork(y * y);
}
}

[Test] public void UsingRhinoMocks() {
const int workResult = 293848;
MockRepository mockery = new MockRepository();
var o = new MyClass {self = mockery.CreateMock<IDoNotOwn>
()};
Expect.Call(o.self.DirtyWork(4)).Return(workResult);
mockery.ReplayAll();
Assert.That(o.Outer(2), Is.EqualTo(workResult));
mockery.VerifyAll();

Tim Barcz

unread,
Apr 19, 2009, 10:10:16 AM4/19/09
to Rhino...@googlegroups.com
I've heard, I think (I could be crazy), that future releases of DynamicProxy won't require virtual.  This was discussion point in an NHibernate discussion I was having at one point.

Tim

Jonathon Rossi

unread,
Apr 19, 2009, 10:41:54 AM4/19/09
to Rhino...@googlegroups.com
That would be nice, but I am not aware of any way this is possible with the CLR, unless you change the IL of the actual class you want to proxy (e.g. PostSharp).
--
Jono

Tuna Toksoz

unread,
Apr 19, 2009, 10:44:37 AM4/19/09
to Rhino...@googlegroups.com
It was using postsharp, IIRC.


Tuna Toksöz
Eternal sunshine of the open source mind.

http://devlicio.us/blogs/tuna_toksoz
http://tunatoksoz.com
http://twitter.com/tehlike

Tim Barcz

unread,
Apr 19, 2009, 11:01:59 AM4/19/09
to Rhino...@googlegroups.com
My apologies

Kenneth

unread,
Apr 19, 2009, 1:54:33 PM4/19/09
to Rhino.Mocks
Why not if the call is via an interface?

public interface IA { void M(){} }
class A : IA { public void M{Console.Out.WriteLine("from A");} } //
non-virtual;
class AProxy : A, IA { public new void M(){Console.Out.WriteLine("from
Proxy"); base.M();} }

IA a = new A();
a.M();
// You get:
from A

IA a = new AProxy();
a.M();
// Then you get:
from Proxy
from A

A a = new AProxy();
a.M();
// I understand this will not work for non-virtual, you get:
from A

On Apr 19, 10:41 am, Jonathon Rossi <j...@jonorossi.com> wrote:
> That would be nice, but I am not aware of any way this is possible with the
> CLR, unless you change the IL of the actual class you want to proxy (e.g.
> PostSharp).
>
>
>
> On Mon, Apr 20, 2009 at 12:10 AM, Tim Barcz <timba...@gmail.com> wrote:
> > I've heard, I think (I could be crazy), that future releases of
> > DynamicProxy won't require virtual.  This was discussion point in an
> > NHibernate discussion I was having at one point.
>
> > Tim
>
Reply all
Reply to author
Forward
0 new messages