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

Spring JUnit中如何初始化Map<String, Map<String,String>>配置属性?

解决JUnit测试中嵌套Map配置未初始化的空指针问题

问题根源

你的测试代码存在两处关键问题:

  1. 测试类错误添加了@ConfigurationProperties(prefix = "someproperties"),该注解仅需作用在配置类(即SomeClient)上。
  2. 用@Mock处理urlMap是错误的——Mockito生成的Mock Map调用get()方法默认返回null,这就是空指针的直接原因。我们需要的是真实的Map实例并填充配置数据,而非Mock对象。

方案一:使用Spring Boot Test上下文自动加载配置

如果希望测试时自动读取配置文件中的urlmap数据,可改用Spring Boot测试上下文,自动处理配置注入:

@SpringBootTest(classes = SomeClient.class)
@EnableConfigurationProperties(SomeClient.class)
@TestPropertySource(locations = "classpath:application-test.properties")
public class SomeClientTest {

    @Autowired
    private SomeClient someClient;

    @MockBean
    private CustomWebClient genericWebClient; // 用@MockBean让Spring管理Mock对象

    @Test
    public void testGetSomething() throws IOException {
        // someClient的urlmap已自动从application-test.properties加载数据
        
        // 原有WebClient Mock逻辑不变
        when(genericWebClient.invoketarget(any(URI.class), any(), any(Class.class), any(HttpMethod.class), any(Some.class),
                anyBoolean(), any(Smething.class))).thenReturn(somemonoresponse);
        when(someUtil.typeCastToMonoResponseEntity(any())).thenReturn(somemonoresponse);

        Mono<ResponseEntity<somemonoresponse>> resp = someClient.getSomething("jhfjhtf6", webExchange);

        StepVerifier.create(resp)
                .consumeNextWith(response -> assertNotNull(response))
                .verifyComplete();
    }
}

说明:

  • @SpringBootTest启动Spring上下文,自动处理@ConfigurationProperties注入,urlmap会读取配置文件中的数据。
  • @MockBean用于替换上下文里的CustomWebClient实例,避免依赖真实的WebClient组件。

方案二:手动初始化urlmap(纯Mockito环境)

若不想启动Spring上下文,继续使用MockitoExtension,可手动给someClient的urlmap赋值:

@ExtendWith(MockitoExtension.class)
public class SomeClientTest {

    private static final String SOME_URL = "/v2/something/{someid}/resource";

    @InjectMocks
    private SomeClient someClient;

    @Mock
    private CustomWebClient genericWebClient;

    @BeforeEach
    void setUp() {
        // 手动构建嵌套Map,模拟配置数据
        Map<String, Map<String, String>> urlMap = new HashMap<>();
        
        // 填充dev环境配置
        Map<String, String> devMap = new HashMap<>();
        devMap.put("url1", "http://something1.com");
        devMap.put("url2", "http://something2.com");
        urlMap.put("dev", devMap);

        // 填充qa环境配置
        Map<String, String> qaMap = new HashMap<>();
        qaMap.put("url1", "http://something1.com");
        qaMap.put("url2", "http://something2.com");
        urlMap.put("qa", qaMap);

        // 必须添加prod环境配置,避免else分支空指针
        Map<String, String> prodMap = new HashMap<>();
        prodMap.put("url2", "http://prod-something2.com");
        urlMap.put("prod", prodMap);

        // 赋值给someClient的urlmap
        someClient.setUrlmap(urlMap);
    }

    @Test
    public void testGetSomething() throws IOException {
        String someID = "jhfjhtf6";
        
        // 原有WebClient Mock逻辑不变
        when(genericWebClient.invoketarget(any(URI.class), any(), any(Class.class), any(HttpMethod.class), any(Some.class),
                anyBoolean(), any(Smething.class))).thenReturn(somemonoresponse);
        when(someUtil.typeCastToMonoResponseEntity(any())).thenReturn(somemonoresponse);

        Mono<ResponseEntity<somemonoresponse>> resp = someClient.getSomething(someID, webExchange);

        StepVerifier.create(resp)
                .consumeNextWith(response -> assertNotNull(response))
                .verifyComplete();
    }
}

说明:

  • 移除测试类上多余的@EnableConfigurationProperties、@TestPropertySource、@ConfigurationProperties注解,纯Mockito环境不处理这些Spring配置注解。
  • 在@BeforeEach中构建完整的嵌套Map,确保包含prod条目,避免else分支触发空指针。

方案三:修正Mockito的Mock使用(不推荐)

若坚持要Mock该Map,需为每个get()调用指定返回值,否则默认返回null:

@ExtendWith(MockitoExtension.class)
public class SomeClientTest {

    @InjectMocks
    private SomeClient someClient;

    @Mock
    private CustomWebClient genericWebClient;

    @Mock
    private Map<String, Map<String, String>> urlMap;

    @BeforeEach
    void setUp() {
        // 模拟prod分支的返回值
        Map<String, String> prodMap = new HashMap<>();
        prodMap.put("url2", "http://prod-something2.com");
        when(urlMap.get("prod")).thenReturn(prodMap);

        // 模拟dev分支的返回值
        Map<String, String> devMap = new HashMap<>();
        devMap.put("url1", "http://something1.com");
        when(urlMap.get("dev")).thenReturn(devMap);

        // 将Mock的Map赋值给someClient
        someClient.setUrlmap(urlMap);
    }

    // 测试方法逻辑不变
}

说明:

  • 该方式需为每个可能的get()调用指定返回值,操作繁琐,不如直接使用真实Map便捷,因此不推荐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 01:02:54