问题与单元测试嘲讽Moq

有人可以帮助我如何设置Mockobjects并验证使用Moq单元测试c#吗?

我的缓存类如下所示:

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;
    }
}

我的界面是

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

我正在使用CacheFactory来调用我的InMemoryCache类:

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;
    }
}

我尝试了下面的模拟对象,无法得到结果。

 [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

    }

有人能帮我,我的数据插入缓存是正确的吗? 还帮助我如何验证单元测试Moq中的缓存数据。 我是单元测试新手,如果需要的话更正我的代码。 我无法验证,因为我正在将数据插入到实现类中的对象缓存中,但是却嘲弄了接口。 我想,如果我可以将两者联系起来,那可能是验证。 不知道,它只是我的猜测。 我很抱歉,如果这是一个愚蠢的问题,但你的帮助真的很感激。

请让我知道你是否需要进一步的细节。

此致Viswa V.

更新方案:

考虑让另一个名为“转换器”的类根据缓存中的成绩标识检索成绩名称。

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();
    }
}

对于这种情况,你能告诉我如何验证? 由于此方法使用缓存来检索值,因此我不确定如何在此处使用模拟。 非常感谢您的帮助。 谢谢。


你似乎误解了嘲笑的用法。 使用mock的原因是测试依赖类而不必担心依赖关系。

假设您有以下课程:

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;
    }
}

为了测试上面的类,你将不得不模拟在ICache函数中注入到类中的ICache对象。 在这种情况下,使用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);

我们使用依赖类所依赖的缓存键“GradeList”来嘲笑ICache返回6个等级。 我们现在可以测试MyDependentClass上的方法正确返回缓存中的计数。 同样,您可以在缓存返回一个空列表或null地方进行测试,以检查在所有情况下依赖类的行为是否正确。

在你的例子中,你想测试InMemoryCache本身,在这种情况下你不想嘲笑任何东西。 我会简单地写这样的测试:

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.

更新的场景

对于更新的场景,不能模拟缓存,因为它是通过CacheFactory上的静态方法检索的。 这可能是为依赖项使用依赖注入的最佳理由之一,而不是在类中自己实例化它们,而不是使用静态类/方法。

我会做什么使Converter类可测试,将注入ICache到类而不是使用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();
    }
}

现在你可以像上面描述的那样嘲笑ICache并测试Convertor类的功能。


看来你对这些概念感到困惑。

如果您想(单元)测试InMemoryCache类的Insert方法,那么您定义的函数不应该模拟InMemoryCache。

Mocking适用于要测试的课程中使用的第三方课程。

事实上,你的插入方法也有一个依赖:

private readonly ObjectCache _objCache = MemoryCache.Default;

所以,你应该以某种方式模拟ObjectCache实例。

但是这次ObjectCache必须从相关接口继承以便在Moq库中使用,即IObjectCache

你应该使用:

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

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

但是ObjectCache类是从IEnumerable和IEnumerable>继承的,所以你不能直接模拟它。 如果你真的需要模拟,你应该使用桥接口(反腐败层)。

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

上一篇: Issue with Unit test Mocking Moq

下一篇: expected result?