JUnit+Mockito测试中如何跳过静态ValidationUtils.invokeValidator验证?
解决静态验证方法Mock问题,跳过验证测试核心业务
嘿,我之前也踩过这个坑!你遇到的问题核心是静态方法的Mock方式不对——ValidationUtils.invokeValidator是个静态方法,而你用的doNothing()是Mockito用来Mock对象非静态方法的语法,直接这么写肯定会报错。而且你不能修改被测代码,那我们就通过Mock静态方法或者调整BindingResult的Mock逻辑来绕过验证,直接测试核心业务。
方案一:用Mockito 3.4+的静态Mock(推荐)
从Mockito 3.4.0版本开始,官方支持了静态方法的Mock,不需要依赖额外的PowerMock,用法更简洁:
- 确保你的项目依赖的Mockito版本≥3.4.0
- 在测试类上添加JUnit扩展(JUnit 5用
@ExtendWith(MockitoExtension.class),JUnit 4用@RunWith(MockitoJUnitRunner.class)) - 在测试方法中用
MockedStatic来静态MockValidationUtils,让它的invokeValidator方法不执行任何操作,也不抛出异常
代码示例
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.MockedStatic; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.ResponseEntity; import org.springframework.validation.BindingResult; import org.springframework.validation.ValidationUtils; import javax.servlet.http.HttpServletRequest; @ExtendWith(MockitoExtension.class) public class MyControllerTest { @InjectMocks private MyController controller; // 你的Controller类 @Mock private Validator validator; @Mock private HttpServletRequest request; @Mock private Dto dto; @Mock private BindingResult result; @Test void testMyFunction() { // 静态Mock ValidationUtils,让invokeValidator不做任何操作 try (MockedStatic<ValidationUtils> mockedValidationUtils = mockStatic(ValidationUtils.class)) { mockedValidationUtils.when(() -> ValidationUtils.invokeValidator(validator, dto, result)) .thenDoNothing(); // 额外:如果想直接走核心业务逻辑,可以Mock result.hasErrors()返回false when(result.hasErrors()).thenReturn(false); // 调用被测方法 ResponseEntity<BasicResponse> response = controller.myFunction(request, dto, result); // 这里写你的断言逻辑,比如验证返回结果 // assertEquals(HttpStatus.OK, response.getStatusCode()); // ... } } }
这个try-with-resources的语法会自动管理静态Mock的生命周期,测试结束后会恢复ValidationUtils的原始行为,不会影响其他测试用例。
方案二:用PowerMock(适配旧版本Mockito)
如果你的项目还在使用低于3.4.0的Mockito,那可以用PowerMock来Mock静态方法:
- 引入PowerMock的依赖(比如Maven依赖)
- 测试类上添加
@RunWith(PowerMockRunner.class)和@PrepareForTest(ValidationUtils.class),告诉PowerMock要处理这个静态类 - 用PowerMock的API来Mock静态方法
代码示例
import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.MockitoJUnitRunner; import org.powermock.api.mockito.PowerMockito; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; import org.springframework.http.ResponseEntity; import org.springframework.validation.BindingResult; import org.springframework.validation.ValidationUtils; import javax.servlet.http.HttpServletRequest; @RunWith(PowerMockRunner.class) @PrepareForTest(ValidationUtils.class) public class MyControllerTest { @InjectMocks private MyController controller; @Mock private Validator validator; @Mock private HttpServletRequest request; @Mock private Dto dto; @Mock private BindingResult result; @Test void testMyFunction() { // Mock静态方法,让invokeValidator不执行任何操作 PowerMockito.mockStatic(ValidationUtils.class); PowerMockito.doNothing().when(ValidationUtils.class); ValidationUtils.invokeValidator(validator, dto, result); // Mock result.hasErrors()返回false,直接进入核心业务 when(result.hasErrors()).thenReturn(false); ResponseEntity<BasicResponse> response = controller.myFunction(request, dto, result); // 断言逻辑 } }
额外小技巧:直接Mock BindingResult的状态
如果你根本不想关心验证步骤,除了Mock静态方法,还可以直接Mockresult.hasErrors()返回false,这样不管验证有没有执行,都会直接进入else块的核心业务逻辑,这也是一种更简单的绕过验证的方式。
内容的提问来源于stack exchange,提问作者acso
相关产品推荐
相关产品推荐

