Mockito "thenThrow" 没有按预期抛出异常
Mockito "thenThrow" doesn't throw the exception when expected
我在尝试测试代表 Rest Client 的 class 时遇到问题。我在 Spring Boot.
中使用 RestTemplate
这是抽象的 RestClient class:
public abstract class RestClient {
...
public RestResponse sendPostRequest(URI baseUri, String resource, IRestRequest restRequest, ClassresponseClass)
throws ServerException, ClientException {
...
try {
RestTemplate restTemplate = new RestTemplate();
response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);
result = response.getBody();
getLogger().debug("[{}] received", result);
return result;
} catch (HttpClientErrorException e) {
throw new ClientException(e.getCause());
} catch (HttpServerErrorException e) {
throw new ServerException(e.getCause());
} catch (Exception e) {
getLogger().error("Error with cause: {}.", e.getMessage());
}
...
}
}
这是实际的实现:
public class ActualRestClient extends RestClient {
public RestResponse sendFetchFileRequest(URI baseUri, FetchFileRequest request) throws ServerException, ClientException {
return sendPostRequest(baseUri, "FETCH_FILE", request, RestResponse.class);
}
}
这是测试:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ActualRestClient.class, RestClient.class})
public class ActualResRestClientTest {
private static final String REQUEST_URI = "something";
@InjectMocks
public ActualRestClient testee;
@Mock
private RestTemplate restTemplate;
@Test(expected = ServerException.class)
public void sendPostRequestWithResponseBody_throwsServerException() throws Exception {
HttpServerErrorException httpServerErrorException = new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR);
when(restTemplate.exchange(Mockito.any(URI.class), eq(HttpMethod.POST), Mockito.any(), eq(FetchFileRequest.class))).thenThrow(httpServerErrorException);
testee.sendFetchFileRequest(new URI(REQUEST_URI), new FetchFileRequest());
}
}
ClientException和ServerException是我通过扩展Exceptionclass创建的异常。
我的问题是在 RestClient class 中捕获了另一个异常(消息:"URI is not absolute")而不是 HttpServerErrorException ,我不明白为什么。谢谢!
正如评论者已经表达的那样:new URI("something")
已经对你不利了。但是即使你传递了一个 "valid" URI,你的代码也不会工作,因为你的理解有误。你看:
RestTemplate restTemplate = new RestTemplate();
response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);
该代码存在于您正在测试的 class 的 方法 中。但@InjectMocks 仅适用于 classes.
的 fields
换句话说:当你的生产代码被执行时,一个 new (完全不同的** ResponseTemplate 实例被创建。因此你的模拟规范是无关紧要的,因为方法是' 首先在您的模拟上调用。
两个选择:
- 将该局部变量转换为您正在测试的 class 的字段(然后注入应该起作用)
- 或者,由于您已经在使用 PowerMock(ito),您 可以 使用该模拟框架来拦截对
new()
. 的调用
我建议您宁愿使用选项一,并避免完全使用 PowerMock(ito) 扩展!
我在尝试测试代表 Rest Client 的 class 时遇到问题。我在 Spring Boot.
中使用 RestTemplate这是抽象的 RestClient class:
public abstract class RestClient {
...
public RestResponse sendPostRequest(URI baseUri, String resource, IRestRequest restRequest, ClassresponseClass)
throws ServerException, ClientException {
...
try {
RestTemplate restTemplate = new RestTemplate();
response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);
result = response.getBody();
getLogger().debug("[{}] received", result);
return result;
} catch (HttpClientErrorException e) {
throw new ClientException(e.getCause());
} catch (HttpServerErrorException e) {
throw new ServerException(e.getCause());
} catch (Exception e) {
getLogger().error("Error with cause: {}.", e.getMessage());
}
...
}
}
这是实际的实现:
public class ActualRestClient extends RestClient {
public RestResponse sendFetchFileRequest(URI baseUri, FetchFileRequest request) throws ServerException, ClientException {
return sendPostRequest(baseUri, "FETCH_FILE", request, RestResponse.class);
}
}
这是测试:
@RunWith(PowerMockRunner.class)
@PrepareForTest({ActualRestClient.class, RestClient.class})
public class ActualResRestClientTest {
private static final String REQUEST_URI = "something";
@InjectMocks
public ActualRestClient testee;
@Mock
private RestTemplate restTemplate;
@Test(expected = ServerException.class)
public void sendPostRequestWithResponseBody_throwsServerException() throws Exception {
HttpServerErrorException httpServerErrorException = new HttpServerErrorException(HttpStatus.INTERNAL_SERVER_ERROR);
when(restTemplate.exchange(Mockito.any(URI.class), eq(HttpMethod.POST), Mockito.any(), eq(FetchFileRequest.class))).thenThrow(httpServerErrorException);
testee.sendFetchFileRequest(new URI(REQUEST_URI), new FetchFileRequest());
}
}
ClientException和ServerException是我通过扩展Exceptionclass创建的异常。 我的问题是在 RestClient class 中捕获了另一个异常(消息:"URI is not absolute")而不是 HttpServerErrorException ,我不明白为什么。谢谢!
正如评论者已经表达的那样:new URI("something")
已经对你不利了。但是即使你传递了一个 "valid" URI,你的代码也不会工作,因为你的理解有误。你看:
RestTemplate restTemplate = new RestTemplate();
response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);
该代码存在于您正在测试的 class 的 方法 中。但@InjectMocks 仅适用于 classes.
的 fields换句话说:当你的生产代码被执行时,一个 new (完全不同的** ResponseTemplate 实例被创建。因此你的模拟规范是无关紧要的,因为方法是' 首先在您的模拟上调用。
两个选择:
- 将该局部变量转换为您正在测试的 class 的字段(然后注入应该起作用)
- 或者,由于您已经在使用 PowerMock(ito),您 可以 使用该模拟框架来拦截对
new()
. 的调用
我建议您宁愿使用选项一,并避免完全使用 PowerMock(ito) 扩展!