billboard
billboard

Reputation: 915

Moq: How to Mock method with function callback as paramenter

I'm trying to mock the following GetOrSet method in InMemoryCache class.

public class InMemoryCache : ICacheService
{
    public T GetOrSet<T>(string cacheKey, Func<T> getItemCallback) where T : class
    {
        T item = MemoryCache.Default.Get(cacheKey) as T;
        if (item == null)
        {
            item = getItemCallback();

            DateTime expireDateTime = new DateTime(DateTime.Today.Year, DateTime.Today.Month, DateTime.Today.Day, 4, 0, 0).AddDays(1);
            MemoryCache.Default.Add(cacheKey, item, expireDateTime);
        }
        return item;
    }
}

In my test, I have

var mockCacheService = new Mock<ICacheService>();
mockCacheService.Setup(x => x.GetOrSet..

Can someone help me fill up the dots?

I'm setting up like this

mockCacheService.Setup(x => x.GetOrSet(It.IsAny<string>(), It.IsAny<Func<object>>()))
                .Returns(new Dictionary<string, string> { { "US", "USA"} });

but, when I make a call like this it returns null

var countries = _cacheService.GetOrSet("CountriesDictionary", () => webApiService.GetCountries())

Upvotes: 0

Views: 1967

Answers (1)

CodingYoshi
CodingYoshi

Reputation: 27009

It depends what you want to test. Here are a few examples:

var mockCacheService = new Mock<ICacheService>();

// Setup the GetOrSet method to take any string as its first parameter and 
// any func which returns string as the 2nd parameter
// When the GetOrSet method is called with the above restrictions, return "someObject"
mockCacheService.Setup( x => x.GetOrSet( It.IsAny<string>(), It.IsAny<Func<string>>() ) )
   .Returns( "someObject" );

// Setup the GetOrSet method and only when the first parameter argument is "Key1" and 
// the second argument is a func which returns "item returned by func"
// then this method should return "someOtherObject"
mockCacheService.Setup( x => x.GetOrSet( "Key1", () => "item returned by func") )
   .Returns( "someOtherObject" );

It has many different methods such as IsIn, IsInRange, IsRegex etc. See which one will suit your needs.

You will then need to verify something on your mock. For example, below I am verifying that the method was called with these exact arguments and only called once. If it was called with "Key1" as the first argument and a func which returns "item returned by func", then this will pass.

mockCacheService.Verify( x => x.GetOrSet( "Key1", () => "item returned by func" ), Times.Once() );

EDIT 1

This is important:

You probably know this but I hope you are not using this to test InMemoryCache.GetOrSet method. The idea here is that you are testing some other class and that class, under certain conditions, better call this mock with that specific setup in the setup method above. If your class under test does not call the mock with "Key1" and does not pass a func which returns "item retuned by func", then the test fails. Which means the logic in your class under test is wrong. NOT this class since you are mocking it all.

Upvotes: 3

Related Questions