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

如何在单元测试中Mock Redis?附现有代码示例

解决Redis单元测试Mock问题的方案

你的核心问题在于静态的RedisConnectorHelper硬耦合了真实Redis连接的创建逻辑,导致单元测试无法替换为Mock实例,进而连接真实环境Redis。以下是两种可行的解决思路:

方案一:重构为依赖注入模式(推荐,符合SOLID)

1. 定义Redis连接提供者接口

public interface IRedisConnectionProvider
{
    ConnectionMultiplexer GetConnection();
}

2. 实现真实环境的连接提供者

public class RedisConnectionProvider : IRedisConnectionProvider
{
    private readonly Lazy<ConnectionMultiplexer> _lazyConnection;

    public RedisConnectionProvider()
    {
        string redisServer = WebConfigurationManager.AppSettings["RedisServer"];
        _lazyConnection = new Lazy<ConnectionMultiplexer>(
            () => ConnectionMultiplexer.Connect($"{redisServer},allowAdmin=true"),
            LazyThreadSafetyMode.PublicationOnly
        );
    }

    public ConnectionMultiplexer GetConnection()
    {
        return _lazyConnection.Value;
    }
}

3. 修改业务服务注入依赖

在你的NotebookService中注入IRedisConnectionProvider,替代直接调用静态类:

public class NotebookService
{
    private readonly IRedisConnectionProvider _redisConnectionProvider;

    // 通过构造函数注入依赖
    public NotebookService(IRedisConnectionProvider redisConnectionProvider)
    {
        _redisConnectionProvider = redisConnectionProvider;
    }

    public IEnumerable<Division> GetDivisons()
    {
        // 通过提供者获取连接
        var db = _redisConnectionProvider.GetConnection().GetDatabase();
        // 你的缓存读取/写入逻辑...
    }
}

4. 编写单元测试

[Test]
public void GetDivisons_ShouldReturnNotNullResult()
{
    // Mock Redis数据库,模拟缓存行为
    var mockDb = new Mock<IDatabase>();
    // 按需设置Mock方法的返回值,比如模拟缓存命中
    // mockDb.Setup(db => db.StringGet(It.IsAny<RedisKey>())).Returns("your-cached-division-data");

    // Mock连接多路复用器,返回Mock的数据库
    var mockMultiplexer = new Mock<IConnectionMultiplexer>();
    mockMultiplexer.Setup(m => m.GetDatabase(It.IsAny<int>(), It.IsAny<object>()))
                   .Returns(mockDb.Object);

    // Mock连接提供者,返回Mock的多路复用器
    var mockConnectionProvider = new Mock<IRedisConnectionProvider>();
    mockConnectionProvider.Setup(p => p.GetConnection())
                          .Returns(mockMultiplexer.Object);

    // 创建服务实例,注入Mock依赖
    var notebookService = new NotebookService(mockConnectionProvider.Object);

    // 执行测试
    var result = notebookService.GetDivisons();

    // 断言结果非空
    Assert.NotNull(result);
    // 可选:验证Redis方法是否被调用
    // mockDb.Verify(db => db.StringGet(It.IsAny<RedisKey>()), Times.Once);
}

方案二:修改静态类添加测试入口(快速适配现有代码)

如果不想大规模重构,可以给RedisConnectorHelper添加静态方法,用于测试时替换连接实例:

1. 修改RedisConnectorHelper

public class RedisConnectorHelper
{
    private static Lazy<ConnectionMultiplexer> _lazyConnection;

    static RedisConnectorHelper()
    {
        InitializeDefaultConnection();
    }

    private static void InitializeDefaultConnection()
    {
        string redisServer = WebConfigurationManager.AppSettings["RedisServer"];
        _lazyConnection = new Lazy<ConnectionMultiplexer>(
            () => ConnectionMultiplexer.Connect($"{redisServer},allowAdmin=true"),
            LazyThreadSafetyMode.PublicationOnly
        );
    }

    // 测试专用:替换连接实例
    public static void SetTestConnection(Lazy<ConnectionMultiplexer> connection)
    {
        _lazyConnection = connection;
    }

    public static ConnectionMultiplexer Connection
    {
        get => _lazyConnection.Value;
    }
}

2. 编写单元测试

[Test]
public void GetDivisons()
{
    // 创建Mock的多路复用器和数据库
    var mockMultiplexer = new Mock<IConnectionMultiplexer>();
    var mockDb = new Mock<IDatabase>();
    mockMultiplexer.Setup(m => m.GetDatabase()).Returns(mockDb.Object);

    // 设置静态类使用Mock连接
    RedisConnectorHelper.SetTestConnection(
        new Lazy<ConnectionMultiplexer>(() => mockMultiplexer.Object)
    );

    // 执行测试
    var result = _notebookService.GetDivisons();
    Assert.NotNull(result);
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.07 21:55:15