Mocking Generic Methods With NMock2
Recently I was asked how to mock a generic method, now that NMock2 supports generics. Here's how:
Suppose you have this interface:
public interface IMyInterface
{
T DoStuff<T>();
}
And this class using IMyInterface:
public class MyClass
{
private IMyInterface mi_;
public MyClass(IMyInterface mi)
{
this.mi_ = mi;
}
public string DoSomething()
{
return this.mi_.DoStuff<string>();
}
}
Now, you want to write a unit test where you validate that if DoStuff<string> returns Ploeh, MyClass.DoSomething will also return Ploeh. On the version of NMock2 currently installed on my laptop, this is easily done like this:
[TestMethod]
public void ValidateDoSomething()
{
Mockery mocks = new Mockery();
IMyInterface mi = mocks.NewMock<IMyInterface>();
Expect.Once.On(mi).Method("DoStuff").Will(Return.Value("Ploeh"));
MyClass mc = new MyClass(mi);
string result = mc.DoSomething();
Assert.AreEqual<string>("Ploeh", result);
mocks.VerifyAllExpectationsHaveBeenMet();
}
The only thing which is slightly surprising here is that the method name expected is DoStuff, without any indications of generics - I first expected that I should have indicated the method name as DoStuff`1, but apparently, NMock2 doesn't care whether you are expecting a generic or non-generic version of a method (if DoStuff had had a non-generic overload).
Note that this is based on a release candidate of NMock2, so there's no guarantee that this will work exactly identical in the final release.
Comments
Anonymous
November 18, 2006
The comment has been removedAnonymous
November 18, 2006
Hi Martin Thank you for the tip! I've been keeping an eye on Rhino Mocks for some time, and I really like that it's not string-based, but type safe. On the other hand, according to the documentation, it currently doesn't support mocking generic methods, and this has scared me away from it so far, since I tend to use these from time to time :)Anonymous
January 14, 2007
Hi Mark, hope you are still reading comments on this post! I've got a (very basic) generic service registry IServiceRegistry which has the generic method GetServiceFor<T> . However when I am mocking this I need to tell NMock what the type T is (so tha I can tell NMock to serve up different mocked services depending on what T is) Any ideas on how this is done?Anonymous
January 14, 2007
Hi Gary Thank you for your comment. As far as I can tell, your scenario looks like it's equivalent with the post's sample code. It sounds to me that your IServiceRegistry corresponds to IMyInterface in the sample, and that your GetServiceFor<T> corresponds to DoStuff<T>, or am I missing something? Since you are asking, I guess I am, but if that is the case, I'll need a bit more information on what it is that you are trying to do.Anonymous
January 14, 2007
wow, prompt response (thanks!) public interface IServiceRegistry { T GetServiceFor<T>(); } [Test] public void ThisDoesNotwork() { Mockery mockery = new Mockery(); IServiceRegistry mockServices = mockery.NewMock<IServiceRegistry>(); IPolicyConfiguration mockPolicyConfig = mockery.NewMock<IPolicyConfiguration>(); IChargingConfiguration mockChargingConfig = mockery.NewMock<IChargingConfiguration>(); // The problem!!! Stub.On(mockServices).Method("GetServiceFor").Will(Return.Value(mockChargingConfig)); Stub.On(mockServices).Method("GetServiceFor").Will(Return.Value(mockPolicyConfig)); // Do test mockery.VerifyAllExpectationsHaveBeenMet(); }Anonymous
January 14, 2007
The comment has been removedAnonymous
January 14, 2007
Thanks! Expect.Once does the trick! Thanks again, Gary.Anonymous
January 15, 2007
Hi Gary Thanks for letting me know. I'm happy I could be of assistance :)Anonymous
October 09, 2007
this is easy and useful sample. many thanks about that.Anonymous
May 30, 2008
In V1.0 on https://sourceforge.net/projects/nmock2/ of NMock2 you can specify type parameters on methods in expectations: Expect.Once.On(mockServices).Method("GetServiceFor", typeof(IPolicyConfiguration)).Will(Return.Value(mockery.NewMock<IPolicyConfiguration>())); Therefore no ordered expectations are needed anymore.Anonymous
October 02, 2008
My NMock tests looks as follows; public interface IMyInterface { string DoStuff<T>(); } [Test] public void ValidateDoSomething() { Mockery mocks = new Mockery(); IMyInterface mi = mocks.NewMock<IMyInterface>(); Expect.Once.On(mi).Method("DoStuff").Will(Return.Value("Ploeh")); mocks.VerifyAllExpectationsHaveBeenMet(); } Here when i try to create a NMock object i am getting a TypeOverloading exception. i.e. when executing line "IMyInterface mi = mocks.NewMock<IMyInterface>();" i am getting following; System.TypeLoadException: Signature of the body and declaration in a method implementation do not match. Type: 'MockObjectType1'. Assembly: 'MockObjects, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'. I am grateful if you can explain the cause for this. Thank You AJAnonymous
October 05, 2008
Hi AJ It's a long time ago I used NMock, and I've never really used NMock2, so I've never seen this particular error before. Do you get the same error if you reproduce my code completely?Anonymous
January 29, 2009
Got interface with generic method similar to described in this blog and tried NMock 2.0 Release Candidate 1 and NMock 2.0 Release Candidate 2. NMock 2.0 Release Candidate 2 gets TypeLoadException. NMock 2.0 Release Candidate 1 works.Anonymous
January 29, 2009
Hi Vladlen Thank you for your comment. May I suggest that you log this as a bug against NMock 2.0 Release Candidate 2, then? Otherwise, you could always just decide to use Rhino Mocks instead ;)Anonymous
June 23, 2009
Check out http://code.google.com/p/nmock2extensions/ it lets you do Stub.On(childScope) .Method(new GenericMethodMatcher("MethodName", typeof(Type1), typeof(Type2)) .Will(Return.Value(NewMock<Type2>())); or .Net 3.5 people can do this... Stub.On(childScope) .Method<Type1, Type3>("MethodName") .Will(Return.Value(NewMock<Type3>()));