Mockito测试含RestTemplate.delete与异常处理的服务方法问题
解决Mockito测试无返回值方法异常转换的问题
你遇到的核心问题是对@InjectMocks注入的对象使用doThrow的方式不对——因为@InjectMocks默认会创建被测试类的真实实例(而非Mock对象),所以不能用Mock的语法去模拟它的方法抛出异常。我们的目标是让真实的服务方法执行,通过Mock依赖的restTemplate抛出异常,来验证服务是否正确转换为自定义异常。
正确的测试实现步骤
- 正确配置Mock和被测试对象:用
@Mock注解创建RestTemplate的Mock实例,用@InjectMocks创建真实的GreetingsService实例(确保依赖注入正确)。 - 指定Mock对象的异常行为:对
restTemplate.delete方法使用doThrow,模拟它抛出404的HttpClientErrorException。 - 验证服务方法的异常输出:调用服务的真实方法,用JUnit的断言捕获并验证是否抛出了预期的
GreetingNotFoundException。
完整测试代码示例
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponentsBuilder; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.doThrow; @ExtendWith(MockitoExtension.class) public class GreetingsServiceTest { @Mock private RestTemplate restTemplate; @InjectMocks private GreetingsService greetingsService; // 真实实例,依赖被注入Mock的restTemplate @Test public void deleteGreetingById_WhenGreetingNotFound_ThrowsCustomException() { Integer testId = 1; String expectedUrl = UriComponentsBuilder.fromHttpUrl("http://localhost:9123/greetings/" + testId) .toUriString(); // 配置Mock:当restTemplate调用delete指定URL时,抛出404异常 doThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND)) .when(restTemplate) .delete(expectedUrl); // 调用真实服务方法,验证是否抛出预期异常 GreetingNotFoundException exception = assertThrows(GreetingNotFoundException.class, () -> greetingsService.deleteGreetingById(testId)); // 额外验证异常消息是否符合预期 assertEquals("Greeting with id: " + testId + " not found.", exception.getMessage()); } }
关键知识点解释
@InjectMocks的作用:它的职责是创建被测试类的真实实例,并将所有标注了@Mock或@Spy的依赖注入到这个实例中。它本身不是Mock对象,所以不能用doThrow来模拟它的方法行为,我们要测试的就是它的真实逻辑。- 无返回值方法的Mock方式:对于
restTemplate.delete这种无返回值的方法,使用doThrow(...).when(mock).method(...)是正确的语法,符合Mockito的规范。如果不想严格匹配URL参数,也可以用anyString()这样的匹配器,比如:doThrow(new HttpClientErrorException(HttpStatus.NOT_FOUND)) .when(restTemplate) .delete(anyString()); - 异常验证的正确姿势:JUnit 5的
assertThrows是推荐的方式,它不仅能验证异常类型,还能捕获异常实例,方便我们进一步验证异常消息、原因等细节,比JUnit 4的expected属性更灵活。
内容的提问来源于stack exchange,提问作者FishingIsLife
相关产品推荐
相关产品推荐

