如何为switch case编写JUnit测试?参数化测试遇异常求助
问题解决步骤
一、解决参数化测试注解冲突问题
你遇到的Method testSwitchCase_SUCCESS should have no parameters错误,核心原因是混用了JUnit 4的JUnitParamsRunner和JUnit 5的参数化注解:
@RunWith(JUnitParamsRunner.class)是JUnit 4生态的参数化测试工具,而@ParameterizedTest、@ValueSource是JUnit 5(Jupiter)的原生参数化注解,两者完全不兼容,导致JUnit无法识别测试方法的参数。
修复方法:
- 彻底移除测试类上的
@RunWith(JUnitParamsRunner.class)注解。 - 确保项目依赖中包含JUnit Jupiter参数化测试依赖(Maven需引入
junit-jupiter-params,Gradle需引入org.junit.jupiter:junit-jupiter-params)。
二、解决NullPointerException问题
待测试的switchCase()方法依赖多个未初始化的成员变量,测试时这些变量为null,直接触发空指针异常。需要逐个处理这些依赖:
需初始化/Mock的依赖项:
repoFactory:Mock该对象,并Mock其内部的ConsentApplicationRepo的findOne方法,确保返回非null的ConsentApplication实例。consentApplicationVo:Mock其getId()方法,返回一个测试用的ID字符串。serviceNameEnum:直接赋值为CrestApiServiceNameEnum的枚举实例,或Mock其getCode()方法返回对应枚举的编码。newCrestApiTrack:初始化一个实例,避免调用setRepRefNo时触发空指针。httpHeaders:初始化HttpHeaders对象,避免调用add方法时触发空指针。custDataApiKey、creditParamApiKey、multiEntitiApiKey:给这些变量赋值测试用的字符串。
三、完整测试代码示例
因为测试的是枚举分支逻辑,推荐用@EnumSource直接传入枚举值,比@ValueSource更直观且不易出错:
import org.junit.jupiter.api.TestInstance; import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.EnumSource; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.springframework.http.HttpHeaders; import static org.mockito.Mockito.*; @TestInstance(TestInstance.Lifecycle.PER_CLASS) public class YourServiceTest { // 替换为你的测试类名 @Mock private RepoFactory repoFactory; // 替换为你的RepoFactory类名 @Mock private ConsentApplicationRepo consentApplicationRepo; // 替换为你的Repo类名 @Mock private ConsentApplicationVo consentApplicationVo; // 替换为你的Vo类名 @Mock private ConsentApplication consentApplication; // 替换为你的实体类名 @InjectMocks private YourService serviceUnderTest; // 替换为包含switchCase方法的类名 // 初始化测试依赖 public YourServiceTest() { MockitoAnnotations.openMocks(this); // 初始化httpHeaders serviceUnderTest.httpHeaders = new HttpHeaders(); // 初始化newCrestApiTrack serviceUnderTest.newCrestApiTrack = new CrestApiTrack(); // 替换为你的类名 // 给各个API密钥赋值 serviceUnderTest.custDataApiKey = "test-cust-key"; serviceUnderTest.creditParamApiKey = "test-credit-key"; serviceUnderTest.multiEntitiApiKey = "test-multi-key"; // Mock repoFactory返回Repo实例 when(repoFactory.getConsentApplicationRepo()).thenReturn(consentApplicationRepo); // Mock Repo的findOne方法 when(consentApplicationRepo.findOne(anyString())).thenReturn(consentApplication); // Mock Vo的getId方法 when(consentApplicationVo.getId()).thenReturn("test-consent-id"); } @ParameterizedTest @EnumSource(CrestApiServiceNameEnum.class) // 自动传入所有枚举值,可通过names属性指定特定值 void testSwitchCase_SUCCESS(CrestApiServiceNameEnum testEnum) { // 设置当前测试的枚举值 serviceUnderTest.serviceNameEnum = testEnum; // 执行待测试方法 serviceUnderTest.switchCase(); // 验证各分支逻辑正确性 switch (testEnum) { case CUST_DATA: assertNull(serviceUnderTest.newCrestApiTrack.getRepRefNo()); assert serviceUnderTest.httpHeaders.getFirst("API-KEY").equals("test-cust-key"); break; case CREDIT_PARAM: assert serviceUnderTest.httpHeaders.getFirst("API-KEY").equals("test-credit-key"); break; case CONFIRM_MUL_ENT: assert serviceUnderTest.httpHeaders.getFirst("API-KEY").equals("test-multi-key"); break; default: // 验证日志输出(若需验证默认分支) verify(serviceUnderTest.LOGGER, times(1)).info(contains("Unexpected value")); } } }
关键说明:
- 使用
@EnumSource直接传递枚举实例,避免手动处理编码转换,逻辑更可靠。 - 通过
@InjectMocks注入待测试类,@Mock注解自动Mock依赖对象。 - 显式初始化待测试类的所有成员变量,从根源避免空指针。
- 针对每个枚举分支添加对应断言,确保分支逻辑符合预期。
内容的提问来源于stack exchange,提问作者user14144231
相关产品推荐
相关产品推荐

