次の方法で共有


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 removed

  • Anonymous
    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 removed

  • Anonymous
    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 AJ

  • Anonymous
    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>()));