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

使用Redis Mock做单元测试时出现NullPointerException问题求助

解决RedisTemplate空指针异常问题

你的空指针异常根源很清晰:你在RegistrationService里手动new了RedisTemplate实例,但这个实例完全脱离了Spring的上下文管理,没有被配置连接工厂(ConnectionFactory)。Spring容器管理的RedisTemplate会自动注入连接工厂并完成初始化,但你自己new出来的RedisTemplate核心组件都是null,调用opsForHash()自然会抛出NPE。

下面是具体的修复步骤:

1. 改用依赖注入获取RedisTemplate,不要手动实例化

把RegistrationService里的RedisTemplate改成通过@Autowired注入,替换掉自己new的代码:

@Import({RedisConfiguration.class}) 
@Service 
public class RegistrationService {

    // 注入Spring容器管理的RedisTemplate实例
    @Autowired
    private RedisTemplate<String, Object> redisTemplate; 

    public String submitApplicationOverview(String overviewRequest) throws IOException {
        ObjectMapper mapper = new ObjectMapper();
        HashMap<String,Object> applicationData = mapper.readValue(overviewRequest, new TypeReference<Map<String,Object>>(){});
        
        // 序列化配置移到统一配置类中,不用在业务代码重复设置
        UUID key = UUID.randomUUID();
        redisTemplate.opsForHash().putAll(key.toString(), applicationData); 
        System.out.println("Application saved:" + overviewRequest);
        return key.toString();
    } 
}

(顺便提一句:方法名和变量名建议遵循Java小驼峰命名规范,我帮你调整了SubmitApplicationOverview和Key的命名)

2. 在配置类中统一配置RedisTemplate的序列化规则

创建或修改RedisConfiguration类,在这里完成RedisTemplate的序列化配置,让所有注入的实例都复用这个配置:

@Configuration
public class RedisConfiguration {

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);
        
        // 配置哈希键值的序列化方式
        template.setHashKeySerializer(new StringRedisSerializer());
        template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        // 可选:配置全局键值的序列化规则
        template.setKeySerializer(new StringRedisSerializer());
        template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
        
        template.afterPropertiesSet();
        return template;
    }
}

3. 给测试环境配置嵌入式Redis的连接工厂

你已经启动了嵌入式RedisServer,但还需要让Spring注入的RedisTemplate连接到这个测试服务器。可以用@TestConfiguration来覆盖生产环境的Redis配置:

@RunWith(SpringRunner.class)
@SpringBootTest
public class RegistrationServiceTest {

    private RedisServer redisServer;
    
    @Autowired
    private RegistrationService registrationService;

    @Before
    public void setup() {
        // 启动默认端口6379的嵌入式Redis
        redisServer = RedisServer.newRedisServer();
        redisServer.start();
    }

    @After
    public void teardown() {
        // 测试结束后关闭Redis,避免占用端口
        if (redisServer != null) {
            redisServer.stop();
        }
    }

    // 测试专用的Redis配置,覆盖生产环境的集群/哨兵配置
    @TestConfiguration
    static class TestRedisConfig {
        @Bean
        public RedisConnectionFactory redisConnectionFactory() {
            // 连接到本地嵌入式Redis
            return new LettuceConnectionFactory("localhost", 6379);
        }
    }

    @Test
    public void testSubmitApplicationOverview() throws IOException {
        String body = "{\n" +
                " \"VehicleCategory\": \"CAR\",\n" +
                " \"EmailAddress\": \"email@email.com\"\n" +
                "}";
        String result = registrationService.submitApplicationOverview(body);
        Assert.assertNotNull("返回的UUID不能为空", result);
        // 可选:验证Redis中是否真的存入了数据
        // Map<Object, Object> storedData = redisTemplate.opsForHash().entries(result);
        // Assert.assertEquals("CAR", storedData.get("VehicleCategory"));
    }
}

额外注意事项

  • 你的application.properties里同时配置了集群、哨兵、URL三种Redis连接方式,这会导致Spring无法确定使用哪种配置。生产环境要只保留符合你实际部署的配置(比如用哨兵就删掉集群和URL的配置);测试环境我们已经通过@TestConfiguration覆盖了配置,不用担心冲突。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 07:23:20