Issue with Unit test Mocking Moq

Could someone help me how to setup Mockobjects and verify using Moq unit testing c#?

My Cache Class is given below:

public class InMemoryCache : ICache
{
    private readonly ObjectCache _objCache = MemoryCache.Default;       

    public void Insert<T>(string cacheKey, T value)
    {
        _objCache.Add(cacheKey, value, DateTimeOffset.MaxValue);
    }
    public T Get<T>(string cacheKey)
    {
        if (cacheKey != null)
            return (T)Convert.ChangeType(_objCache.Get(cacheKey), typeof(T));
        else
            return default(T);
    }
    public bool Exists<T>(string cacheKey)
    {
        return _objCache.Get(cacheKey) != null;
    }
}

And my Interface is

 public interface ICache
 {
    void Insert<T>(string cacheKey, T value);
    T Get<T>(string cacheKey);
    bool Exists<T>(string cacheKey);        
 }

I am using CacheFactory to call my InMemoryCache Class:

public class CacheFactory
{
    public static ICache Cache { get; set; }

    public static void Insert<T>(string cacheKey, T value)
    {
        Cache.Insert<T>(cacheKey, value);
    }

    public static T Get<T>(string cacheKey)
    {
        return Cache.Get<T>(cacheKey);
    }

    public static bool Exists<T>(string cacheKey)
    {
        return Cache.Get<T>(cacheKey) != null;
    }
}

I tried Mock Object like below and unable to get the result.

 [Fact()]
    public void CacheManager_Insert_Test()
    {
        string cacheKey = "GradeList";

        Mock<ICache> mockObject = new Mock<ICache>();
        List<Grade> grades = new List<Grade>
        {
            new Grade() {Id = 1, Name = "A*"},
            new Grade() {Id = 2, Name = "A"},
            new Grade() {Id = 3, Name = "B"},
            new Grade() {Id = 4, Name = "C"},
            new Grade() {Id = 5, Name = "D"},
            new Grade() {Id = 6, Name = "E"}
        };

        var mockedObjectCache = new Mock<ICache>();
        // Setup mock's Set method

        mockedObjectCache.Setup(m => m.Insert(cacheKey, grades));

       // How to get the Mocked data and verify it here

    }

Could some one help me that my data insertion to cache is correct? Also help me how to verify the cache data in unit test Moq. I am new to unit testing and correct my code if needed. I am not able to verify since I am inserting data to object cache in my implementation class but mocking the interface. I suppose if I could relate both, It might be verifying. Not sure, its just my guess. I am sorry if this is silly question, However your help is really appreciated.

please let me know if you need any details further on this.

Regards, Viswa V.

Updated Scenario:

Consider having another class named "Convertor" which retrieves the Grade name based on the Grade ID from cache.

public class Convertor
{ 
    // Gets Grade ID and Displays Grade Name
    public string GetGradeName(int gradeId)
    {
        var gradeList = CacheFactory.Cache.Get<List<Grade>>(CacheKeys.Grades);
        return gradeList.Where(x => x.Id == gradeId).Select(x => x.Name).FirstOrDefault();
    }
}

For this case, Can you tell me how to verify this? Since this method is using cache to retrieve value, I am not sure how to use mock here. Your help is greatly appreciated. Thanks.


You seem to be misunderstanding the usage of mocks. The reason for using mocks is to test dependent classes without worrying on the dependencies.

Let's say you have the following class:

public class MyDependentClass {
    private readonly ICache _cache;
    public MyDependentClass(ICache cache)
    {
        _cache = cache;
    }

    public int CountGradesInCache()
    {
        // Behavior depends on what's in the _cache object
        return _cache.Get<List<Grade>>("GradeList").Count;
    }
}

In order to test the above class you would have to mock the ICache object that is injected into the class in the constructor. In this case it would be sensible to use Mock :

    string cacheKey = "GradeList";

    Mock<ICache> mockObject = new Mock<ICache>();
    List<Grade> grades = new List<Grade>
    {
        new Grade() {Id = 1, Name = "A*"},
        new Grade() {Id = 2, Name = "A"},
        new Grade() {Id = 3, Name = "B"},
        new Grade() {Id = 4, Name = "C"},
        new Grade() {Id = 5, Name = "D"},
        new Grade() {Id = 6, Name = "E"}
    };

    var mockedObjectCache = new Mock<ICache>();
    // Setup mock's Set method

    mockedObjectCache.Setup(m => m.Get(It.Is<string>(cacheKey))).Return(grades);

    // Test that the dependent class acts correctly according to the grades that exist in the cache
    var myDependentClass = new myDependentClass(mockedObjectCache.Object);
    var gradesCount = myDependentClass.CountGradesInCache();

    Assert.AreEqual(6, gradesCount);

We mock the ICache to return 6 grades using the cache key "GradeList", which the dependent class relies on. We can now test that the method on MyDependentClass correctly returns the count in the cache. Likewise, you could make a test where the cache returns an empty list or null to check that the behavior of the dependent class is correct in all cases.

It seems in your example you want to test the InMemoryCache itself, in which case you would not want to mock anything. I would simply write tests like this:

var cache = new InMemoryCache();
var list = new List<Grade> { ... };
var cache.Insert("GradeList", list);

var cachedList = cache.Get<List<Grade>>("GradeList");

// Assert that the list retrieved from cache has the expected values.

Updated scenario

For your updated scenario you cannot mock the cache, as it is retrieved by a static method on the CacheFactory . This is probably one of the best reasons to use dependency-injection for your dependencies, instead of instantiating them yourself in the class or instead of using static classes/methods.

What I would do to make the Converter class testable, would be to inject ICache into the class instead of using the CacheFactory :

public class Convertor
{ 
    private readonly ICache _cache;

    public Convertor(ICache cache)
    {
        _cache = cache;
    }

    public string GetGradeName(int gradeId)
    {
        var gradeList = _cache.Get<List<Grade>>(CacheKeys.Grades);
        return gradeList.Where(x => x.Id == gradeId).Select(x => x.Name).FirstOrDefault();
    }
}

Now you would be able to mock the ICache and test the functionality of the Convertor class like I described above.


It seems that you are confused in the conceptions.

If you want to (unit) test the Insert method of your InMemoryCache class, you definetaly should not mock the InMemoryCache.

Mocking is for the 3rd party classes used in the class you want to test.

In fact you have also a dependency in your insert method:

private readonly ObjectCache _objCache = MemoryCache.Default;

So, you should mock the ObjectCache instance somehow.

But this time ObjectCache must inherited from related interface in order to be used in Moq lib, ie IObjectCache

And you should use:

var mockObjectCache = new Mock<IObjectCache>();
...

//Verifying:
mockObjectCache.Verify(cache => cache.Add(It.IsAny<string>())).Should().Be(true);

However ObjectCache class is inherited from IEnumerable and IEnumerable>, so you cannot mock it directly. You should use a bridge interface (anti corruption layer) if you really need to mock.

链接地址: http://www.djcxy.com/p/35346.html

上一篇: Moq设置导致null

下一篇: 问题与单元测试嘲讽Moq