Moq:如何模拟函数回调作为参数的方法

Moq: How to Mock method with function callback as paramenter

我正在尝试在 InMemoryCache 中模拟以下 GetOrSet 方法 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;
    }
}

在我的测试中,我有

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

有人可以帮我填点吗?

我是这样设置的

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

但是,当我这样打电话时,它 returns null

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

这取决于你想测试什么。这里有几个例子:

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有很多不同的方法,例如IsInIsInRangeIsRegex等等,看看哪一种适合你的需要。

然后您需要在模拟中验证一些内容。例如,下面我正在验证该方法是否使用这些确切的参数调用并且只调用了一次。如果它以 "Key1" 作为第一个参数和一个 returns "item returned by func" 的函数调用,那么这将通过。

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

编辑 1

这很重要:

您可能知道这一点,但我希望您不要用它来测试 InMemoryCache.GetOrSet 方法。这里的想法是,您正在测试其他一些 class 和 class,在某些条件下,最好使用上面 setup 方法中的特定设置调用此模拟。如果您的 class 被测不使用 "Key1" 调用模拟并且不传递 returns "item retuned by func" 的函数,则测试失败。这意味着您的 class 被测逻辑是错误的。不是这个 class 因为你在嘲笑这一切。