无法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
相关产品推荐
相关产品推荐

