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

无法Mock构造方法中初始化的类属性问题求助

问题

编写JUnit测试时,Mock ElasticSearchConnections 后,AuditElasticService 中的 elasticSearchOperationsServiceMap 始终为null,调用createAliases方法时触发NullPointerException,提示Map.get返回值为null。

AuditElasticService类

@Service
public class AuditElasticService {
    private final Map<String,ElasticSearchOperationsService> elasticSearchOperationsServiceMap;

    public AuditElasticService(ElasticSearchConnections elasticSearchConnections) {
        this.elasticSearchOperationsServiceMap = elasticSearchConnections.applyToAllConnections(ElasticSearchOperationsService::new);
    }

    public void createAliases(String ssid, EnvironmentStage environmentStage) {
        String aliasName = "testAudit";
        String indexNameTemplate = "testTemplate";
        String environment = EnvironmentStage.PRODUCTION.equals(environmentStage) ? "prod" : "dev";

        elasticSearchOperationsServiceMap.get(environment).addAliases(aliasName, indexNameTemplate);
    }
}

ElasticSearchConnections配置类

@Component
public class ElasticSearchConnections {
    @Getter
    private final Map<String, ElasticSearchConnection> connections;
    private ElasticSearchConfigurations elasticSearchConfigurations;

    public ElasticSearchConnections(ElasticSearchConfigurations elasticSearchConfigurations) {
        connections = elasticSearchConfigurations.getConfigurationMap().entrySet().stream()
                .collect(Collectors.toMap(Map.Entry::getKey, this::getElasticSearchConnection));
    }

    private ElasticSearchConnection getElasticSearchConnection(Map.Entry<String, ElasticSearchConfiguration> entry) {
        ElasticSearchConfiguration elasticSearchConfiguration = entry.getValue();
        return new ElasticSearchConnection(elasticSearchConfiguration, new KeyTabCookieProvider(elasticSearchConfiguration.getKerberosDetail()));
    }

    public ElasticSearchConnection getByEnv(String environment) {
        return connections.get(environment);
    }

    public <T> Map<String, T> applyToAllConnections(Function<ElasticSearchConnection, T> function) {
        return connections.entrySet().stream().collect(Collectors.toMap(Map.Entry::getKey, function.compose(Map.Entry::getValue)));
    }

}

失效的测试类代码

@ExtendWith(MockitoExtension.class)
class AuditElasticServiceTest {

    private AuditElasticService auditElasticService;
    @Mock
    private ElasticSearchConnections elasticSearchConnections;
    @Mock
    private ElasticSearchOperationsService elasticSearchOperationsService;

    @BeforeEach
    void setUp() {
        auditElasticService = new AuditElasticService(elasticSearchConnections);
    }

    @Test
    @DisplayName("should create a new flow when provided with a title")
    void testCreateAliases() {
        String aliasName = "testAudit";
        String indexNameTemplate = "testTemplate";
        when(elasticSearchConnections.applyToAllConnections(any())).thenReturn(Map.of("dev", elasticSearchOperationsService));
        doNothing().when(elasticSearchOperationsService).addAliases(aliasName, indexNameTemplate);

        auditElasticService.createAliases(testSsid, EnvironmentStage.DEVELOPMENT);

        verify(elasticSearchConnections, times(1)).applyToAllConnections(any());
        verify(elasticSearchOperationsService, times(1)).addAliases(aliasName, indexNameTemplate);
    }

}

解决方案

问题核心是Mock时机错误:AuditElasticService的构造方法在setUp中就会调用elasticSearchConnections.applyToAllConnections,但此时Mock的返回值还未设置,导致elasticSearchOperationsServiceMap被初始化为null。

修改后的测试类代码

@ExtendWith(MockitoExtension.class)
class AuditElasticServiceTest {

    private AuditElasticService auditElasticService;
    @Mock
    private ElasticSearchConnections elasticSearchConnections;
    @Mock
    private ElasticSearchOperationsService elasticSearchOperationsService;
    // 补充缺失的testSsid定义
    private final String testSsid = "test-ssid";

    @BeforeEach
    void setUp() {
        // 先设置Mock返回值,再实例化AuditElasticService
        when(elasticSearchConnections.applyToAllConnections(any(Function.class)))
                .thenReturn(Map.of("dev", elasticSearchOperationsService));
        auditElasticService = new AuditElasticService(elasticSearchConnections);
    }

    @Test
    @DisplayName("should create aliases successfully")
    void testCreateAliases() {
        String aliasName = "testAudit";
        String indexNameTemplate = "testTemplate";
        
        doNothing().when(elasticSearchOperationsService).addAliases(aliasName, indexNameTemplate);

        auditElasticService.createAliases(testSsid, EnvironmentStage.DEVELOPMENT);

        verify(elasticSearchConnections, times(1)).applyToAllConnections(any());
        verify(elasticSearchOperationsService, times(1)).addAliases(aliasName, indexNameTemplate);
    }

}

额外注意事项

  • 确保EnvironmentStage枚举包含DEVELOPMENT和PRODUCTION值,否则环境判断逻辑会出错
  • 若需测试生产环境场景,只需在Mock返回值中添加"prod"对应的ElasticSearchOperationsService实例即可

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 00:10:29