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

单元测试在IntelliJ IDEA中运行成功,Maven命令执行失败

问题描述

我编写了一个简单的单元测试,代码如下:

@Test
public void testHandleInterruptedException() {
  InterruptedException exception = Mockito.mock(InterruptedException.class);
  Assertions.assertNotNull(YammerService.handleInterruptedException(exception, Boolean.TRUE));
  Assertions.assertNotNull(YammerService.handleInterruptedException(exception, Boolean.FALSE));
}

奇怪的是,这个测试在IntelliJ IDEA中运行通过,但使用Maven构建命令执行时失败。

对应的handleInterruptedException方法实现很简单:

public static KendraConnectorException handleInterruptedException(
  InterruptedException e, boolean isContinuable) {

  return isContinuable ? new ContinuableInternalServerError(
    "Current thread has been interrupted", e)
    : new InternalServerError("Please try again later", e);
}

我不确定Maven执行失败的原因,补充完整的YammerServiceTest测试类代码,可能问题出在测试类中:

package com.amazonaws.kendra.connector.yammer.client;

import com.amazonaws.kendra.connector.sdk.exception.BadRequestException;
import com.amazonaws.kendra.connector.sdk.exception.ContinuableInternalServerError;
import com.amazonaws.kendra.connector.yammer.configuration.YammerConfiguration;
import com.amazonaws.kendra.connector.yammer.rest.client.api.MyselfApi;
import com.amazonaws.kendra.connector.yammer.service.UserService;
import feign.FeignException;
import java.net.UnknownHostException;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.MockedStatic;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class YammerServiceTest {
  private MockedStatic<UserService> userService =
      Mockito.mockStatic(UserService.class);
  private YammerConfiguration yammerConfiguration =
      Mockito.mock(YammerConfiguration.class);
  private MyselfApi myselfApi = Mockito.mock(MyselfApi.class);

  @BeforeEach
  public void setUp() {
    userService.when(() -> UserService.getMyselfApi(Mockito.any()))
        .thenReturn(myselfApi);
    Mockito.when(myselfApi.getCurrentUser()).thenReturn(DataProvider.getUser());
    Mockito.when(yammerConfiguration.getHostUrl()).thenReturn(DataProvider.URL);
    Mockito.when(yammerConfiguration.getAuthType()).thenReturn(DataProvider.OAUTH2);
    Mockito.when(yammerConfiguration.getClientId()).thenReturn(DataProvider.CLIENT_ID);
    Mockito.when(yammerConfiguration.getClientSecret()).thenReturn(DataProvider.CLIENT_SECRET);
    Mockito.when(yammerConfiguration.getUserName()).thenReturn(DataProvider.USER_NAME);
    Mockito.when(yammerConfiguration.getPassword()).thenReturn(DataProvider.PASSWORD);
    Mockito.when(yammerConfiguration.getScope()).thenReturn(DataProvider.SCOPE);
  }

  @AfterEach
  void tearDown() {
    if (!Objects.isNull(userService)) {
      userService.close();
    }
    userService = null;
  }

  @Test
  public void testReTestConnection() {
    YammerConfiguration yammerConfiguration = Mockito.mock(YammerConfiguration.class);
    YammerService yammerService = new YammerService();
    Assertions.assertTrue(yammerService.reTestConnection(yammerConfiguration));
  }

  @Test
  public void testTestConnection() {
    YammerService yammerService = new YammerService();
    Assertions.assertTrue(yammerService.testConnection(yammerConfiguration));
  }

  @Test
  public void testReTestConnectionWhenFeignExceptionIsThrown() {
    YammerConfiguration configuration = Mockito.mock(YammerConfiguration.class);
    FeignException exception = Mockito.mock(FeignException.class);
    Mockito.when(configuration.getHostUrl()).thenThrow(exception);
    Mockito.when(exception.status()).thenReturn(429);
    Assertions.assertFalse(YammerService.reTestConnection(configuration));
  }

  @Test
  public void testReTestConnectionWhenFeignExceptionIsThrown_1() {
    YammerConfiguration configuration = Mockito.mock(YammerConfiguration.class);
    FeignException exception = Mockito.mock(FeignException.class);
    Mockito.when(configuration.getHostUrl()).thenThrow(exception);
    Mockito.when(exception.status()).thenReturn(430);
    Assertions.assertFalse(YammerService.reTestConnection(configuration));
  }

  @Test
  public void testTestConnectionWhenFeignExceptionIsThrown() {
    YammerConfiguration configuration = Mockito.mock(YammerConfiguration.class);
    FeignException exception = Mockito.mock(FeignException.class);
    Mockito.when(configuration.getHostUrl()).thenReturn(DataProvider.URL);
    Mockito.when(configuration.getAuthType()).thenThrow(exception);
    Mockito.when(exception.status()).thenReturn(430);
    Mockito.when(exception.getCause()).thenReturn(exception);
    Assertions.assertThrows(BadRequestException.class,
        () -> YammerService.testConnection(configuration));
  }

  //@Test
  public void testTestConnectionWithThrotlingWhenFeignExceptionIsThrown() {
    YammerConfiguration configuration = Mockito.mock(YammerConfiguration.class);
    FeignException exception = Mockito.mock(FeignException.class);
    Mockito.when(configuration.getHostUrl()).thenReturn(DataProvider.URL);
    Mockito.when(configuration.getAuthType()).thenThrow(exception);
    Mockito.when(exception.status()).thenReturn(429);
    Mockito.when(exception.getCause()).thenReturn(exception);
    Assertions.assertThrows(BadRequestException.class,
        () -> YammerService.testConnection(configuration));
  }

  @Test
  public void testHandleInterruptedException() {
    InterruptedException exception = new InterruptedException("InterruptedException");
    Assertions.assertNotNull(YammerService.handleInterruptedException(exception, Boolean.TRUE));
    Assertions.assertNotNull(YammerService.handleInterruptedException(exception, Boolean.FALSE));
  }

  @Test
  public void testTestConnectionWhenNotAuth2() {
    YammerService yammerService = new YammerService();
    List<Integer> waitTimeList =
        Arrays.asList(1);
    FeignException feignException = Mockito.mock(FeignException.class);
    Mockito.when(feignException.status()).thenReturn(429);
    Mockito.when(feignException.getCause()).thenReturn(new UnknownHostException());
    Mockito.when(yammerConfiguration.getAuthType()).thenReturn(DataProvider.OAUTH);
    userService.when(() -> UserService.getMyselfApi(Mockito.any()))
        .thenThrow(feignException);
    Assertions.assertThrows(BadRequestException.class, () ->
        yammerService.testConnection(yammerConfiguration));
  }

  @Test
  public void testTestConnectionFeignExceptionIsThrown() {
    YammerService yammerService = new YammerService();
    List<Integer> waitTimeList =
        Arrays.asList(1);
    FeignException feignException = Mockito.mock(FeignException.class);
    Mockito.when(feignException.status()).thenReturn(429);
    Mockito.when(feignException.getCause()).thenReturn(new Exception());
    Mockito.when(yammerConfiguration.getAuthType()).thenReturn(DataProvider.OAUTH);
    userService.when(() -> UserService.getMyselfApi(Mockito.any()))
        .thenThrow(feignException);
    Thread.currentThread().interrupt();
    Assertions.assertThrows(ContinuableInternalServerError.class, () ->
        yammerService.testConnection(yammerConfiguration));
  }

  @Test
  public void testTestConnectionWhenCauseIsNull() {
    YammerService yammerService = new YammerService();
    List<Integer> waitTimeList =
        Arrays.asList(1);
    FeignException feignException = Mockito.mock(FeignException.class);
    Mockito.when(feignException.status()).thenReturn(429);
    Mockito.when(feignException.getCause()).thenReturn(null);
    Mockito.when(yammerConfiguration.getAuthType()).thenReturn(DataProvider.OAUTH);
    userService.when(() -> UserService.getMyselfApi(Mockito.any()))
        .thenThrow(feignException);
    Assertions.assertThrows(BadRequestException.class, () ->
        yammerService.testConnection(yammerConfiguration));
  }
}
问题原因与解决方案

1. 线程中断状态未重置导致后续测试异常

在testTestConnectionFeignExceptionIsThrown方法中,调用了Thread.currentThread().interrupt();但未在测试结束后清除线程的中断状态。Maven默认串行执行测试,若该测试在testHandleInterruptedException之前执行,会导致后续测试线程的中断标志始终为true。部分JUnit内部逻辑或断言操作会检查线程中断状态,进而抛出未预期的异常导致测试失败。

修复方法:在该测试方法中添加finally块,清除线程中断状态:

@Test
public void testTestConnectionFeignExceptionIsThrown() {
  try {
    YammerService yammerService = new YammerService();
    List<Integer> waitTimeList = Arrays.asList(1);
    FeignException feignException = Mockito.mock(FeignException.class);
    Mockito.when(feignException.status()).thenReturn(429);
    Mockito.when(feignException.getCause()).thenReturn(new Exception());
    Mockito.when(yammerConfiguration.getAuthType()).thenReturn(DataProvider.OAUTH);
    userService.when(() -> UserService.getMyselfApi(Mockito.any()))
        .thenThrow(feignException);
    Thread.currentThread().interrupt();
    Assertions.assertThrows(ContinuableInternalServerError.class, () ->
        yammerService.testConnection(yammerConfiguration));
  } finally {
    // 清除线程中断状态,避免影响后续测试
    Thread.interrupted();
  }
}

2. 静态Mock创建时机不当导致状态冲突

测试类中userService静态Mock是在成员变量初始化时创建的,而JUnit Jupiter每个测试方法都会创建一个新的测试类实例。这会导致多个静态Mock实例重叠,前一个实例的tearDown关闭静态Mock后,后续实例的静态Mock可能出现状态异常,在Maven的测试执行流程中更容易触发问题。

修复方法:将静态Mock的创建移到setUp方法中,确保每个测试方法前都创建全新的静态Mock:

// 修改成员变量声明,去掉初始化逻辑
private MockedStatic<UserService> userService;

@BeforeEach
public void setUp() {
  // 在每个测试前创建新的静态Mock
  userService = Mockito.mockStatic(UserService.class);
  
  userService.when(() -> UserService.getMyselfApi(Mockito.any()))
      .thenReturn(myselfApi);
  // 其他Mock设置逻辑...
}

3. 可选优化:避免Mock InterruptedException

InterruptedException是受检异常,直接实例化而非Mock更符合实际场景,也能避免Mockito对异常类Mock可能带来的潜在问题(比如部分异常方法的默认行为被Mock覆盖)。你已经在修改后的测试代码中改成了new InterruptedException,这部分可以保留。

完成以上修改后,重新执行Maven构建命令,测试应该能正常通过。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 05:36:22