You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过XUnit Mock测试在Redis缓存中存储对象?

Redis缓存单元测试:正确配置Mock实现对象存储与读取

问题场景

在为自定义Redis缓存操作类CacheAccessor编写单元测试时,尝试MockIDatabase模拟Redis存储Dog对象,但调用GetAsync时返回的是类名{AppServices.Models.Dog},而非预期的带属性的对象,且出现解析错误。核心问题在于Mock时用了pet.ToString(),而实际Redis存储的是JSON序列化后的字符串,与CacheAccessor中用JsonConvert.DeserializeObject反序列化的逻辑不匹配。

现有测试代码

Dog pet = new Dog {
    name = "Jon",
    id = "1234"
};

var fakeDB = new Mock<IDatabase>();
var cacheAccessor = new CacheAccessor(fakeDB.Object);

// 错误的Mock配置:返回ToString()结果而非JSON
fakeDB.Setup(t => t.StringGetAsync(It.IsAny<RedisKey>(), It.IsAny<CommandFlags>()))
      .Returns(Task.Run<RedisValue>(() => pet.ToString()));

var response = await cacheAccessor.GetAsync(key); // 解析错误,返回类名字符串

CacheAccessor的GetAsync方法

public async Task<Pet> GetAsync(string key, Type petType = null)
{
    var res = await this.cacheDatabase.StringGetAsync(key).ConfigureAwait(false);
    // 代码存在变量名不一致问题(res vs responseText),需修正
    var deserializedResponse = JsonConvert.DeserializeObject(responseText, petType);
    return deserializedResponse != null ? (Pet)deserializedResponse : null;
}

解决方案

1. 修正Mock的返回值为JSON序列化字符串

因为CacheAccessor用JSON反序列化,所以Mock的StringGetAsync必须返回对象序列化后的JSON字符串,而非默认的ToString()结果。

修改后的测试代码:

Dog pet = new Dog {
    name = "Jon",
    id = "1234"
};

var fakeDB = new Mock<IDatabase>();
var cacheAccessor = new CacheAccessor(fakeDB.Object);

// 正确Mock:返回序列化后的JSON字符串
var serializedPet = JsonConvert.SerializeObject(pet);
fakeDB.Setup(t => t.StringGetAsync(It.IsAny<RedisKey>(), It.IsAny<CommandFlags>()))
      .ReturnsAsync(new RedisValue(serializedPet));

var response = await cacheAccessor.GetAsync(key, typeof(Dog));
// 此时response应为包含name和id属性的Dog对象

2. 修正CacheAccessor中的变量名错误

原GetAsync方法中,获取到的res变量未被使用,反而引用了未定义的responseText,这会导致运行时错误,需修正为:

public async Task<Pet> GetAsync(string key, Type petType = null)
{
    var res = await this.cacheDatabase.StringGetAsync(key).ConfigureAwait(false);
    var deserializedResponse = JsonConvert.DeserializeObject(res.ToString(), petType);
    return deserializedResponse != null ? (Pet)deserializedResponse : null;
}

3. 可选:验证Mock方法的调用(增强测试严谨性)

如果需要确保StringGetAsync被正确调用,可以在测试末尾添加验证:

fakeDB.Verify(t => t.StringGetAsync(It.Is<RedisKey>(k => k == key), It.IsAny<CommandFlags>()), Times.Once);

内容的提问来源于stack exchange,提问作者HackerMan33453

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 06:55:16