Moq4: Getting errors when attempting to setup a method with an out parameter

Created on 31 Aug 2017  路  2Comments  路  Source: moq/moq4

I am having a very difficult time attempting to mock the ASP.Net Core IMemoryCache object. I have the mock set up as follows:

var memoryCacheMoq = new Mock<IMemoryCache>();
Lookup dummy = new Lookup {  };
memoryCacheMoq.Setup(m => m.TryGetValue(It.IsAny<object>(), out dummy)).Returns(false);

I want the method to return false so my database mock performs what it's supposed to do.

When I debug this, I get the following error when it gets to the setup line:

Message: System.NotSupportedException : Invalid setup on an extension method: m => m.TryGetValue<Lookup>(It.IsAny<Object>(), .dummy)

From everything I've read, and even watched an example on PluralSight, this is the way to set this up.

Any assistance is greatly appreciated! Thank you.

question

Most helpful comment

@sspringer - Note that there are two methods on IMemoryCache called TryGetValue, one of them being an extension method:

  1. bool TryGetValue(object key, out object value) defined in Microsoft.Extensions.Caching.Memory.IMemoryCache
  2. bool TryGetValue<TItem>(this object key, out TItem value) defined in Microsoft.Extensions.Caching.Memory.CacheExtensions

You're setting up the latter overload (2), since your dummy variable is not of type object (and you're explicitly specifying the generic type parameter, as well). Extension methods are static methods and as such cannot be intercepted / dealt with by Moq (this is a well-known limitation that you'll find in most other mocking frameworks), therefore the error message.

Here's something for you to try: Drop the explicit generic type parameter specification, and declare dummy as object, so that you'll set up the non-generic interface method instead of the generic extension method. I'd wager that the extension method is using the interface method internally and simply decorating it with a type cast from object to TItem, so setting up the interface method might give you the desired effect. Also, chances are that you're not actually going to use the value stored in dummy anyway, so you're not loosing much by giving up some type accuracy.

memoryCacheMock.Setup(m => m.TryGetValue(It.IsAny<object>(), out object dummy)).Returns(false);

Does that resolve your problem?

All 2 comments

@sspringer - Note that there are two methods on IMemoryCache called TryGetValue, one of them being an extension method:

  1. bool TryGetValue(object key, out object value) defined in Microsoft.Extensions.Caching.Memory.IMemoryCache
  2. bool TryGetValue<TItem>(this object key, out TItem value) defined in Microsoft.Extensions.Caching.Memory.CacheExtensions

You're setting up the latter overload (2), since your dummy variable is not of type object (and you're explicitly specifying the generic type parameter, as well). Extension methods are static methods and as such cannot be intercepted / dealt with by Moq (this is a well-known limitation that you'll find in most other mocking frameworks), therefore the error message.

Here's something for you to try: Drop the explicit generic type parameter specification, and declare dummy as object, so that you'll set up the non-generic interface method instead of the generic extension method. I'd wager that the extension method is using the interface method internally and simply decorating it with a type cast from object to TItem, so setting up the interface method might give you the desired effect. Also, chances are that you're not actually going to use the value stored in dummy anyway, so you're not loosing much by giving up some type accuracy.

memoryCacheMock.Setup(m => m.TryGetValue(It.IsAny<object>(), out object dummy)).Returns(false);

Does that resolve your problem?

That did the trick! Now I have to figure out how to circumvent the "Set" extension method. Grrr.

Anyway, that did solve my immediate issue. Thanks!

Was this page helpful?
0 / 5 - 0 ratings