I am trying to cover the circuitBreaker fallback method from the below service class
@Component
public class UserService {
private static final String UNABLE_TO_CONNECT_TO_USER_SERVICE ="User service not available";
@Value("${user.service.url}")
private String baseUrl;
@Value("${user.service.username}")
private String userName;
@Value("${user.service.password}")
private String password;
public UserService(
RestTemplateBuilder restTemplateBuilder,
@Qualifier("userService_client_factory")
HttpComponentsClientHttpRequestFactory httpComponentsClientHttpRequestFactory) {
var template = restTemplateBuilder.build();
template.setRequestFactory(httpComponentsClientHttpRequestFactory);
this.restTemplate = template;
}
@CircuitBreaker(name = "userservice", fallbackMethod = "fallback")
@Loggable
public User getUser(String userId) {
try {
LOGGER.debug("calling getUser for userId {}", userId);
ResponseEntity<User> responseEntity =
restTemplate.exchange(
buildUrl("/v2/{user-id}/user", userId),
HttpMethod.GET,
new HttpEntity<>(buildHeaders()),
new ParameterizedTypeReference<User>() {});
return responseEntity.getBody();
} catch (HttpServerErrorException | ResourceAccessException e) {
throw new ServiceInvokeException(UNABLE_TO_CONNECT_TO_USER_SERVICE, e);
} catch (RestClientException e) {
throw new UserException(e.getMessage(), "Get User failed");
}
}
@SuppressWarnings("all")
private User fallback(String userId, ServiceInvokeException e) {
throw new ServiceInvokeException(
format(UNABLE_TO_CONNECT_TO_USER_SERVICE, e.getMessage()), e);
}
private HttpHeaders buildHeaders() {
var headers = new HttpHeaders();
headers.setAccept(singletonList(APPLICATION_JSON));
headers.setContentType(APPLICATION_JSON);
headers.setBasicAuth(userName, password);
return headers;
}
private URI buildUrl(String path, String userId) {
Map<String, String> pathParameters = new HashMap<>();
pathParameters.put("user-id", userId);
String urlPath = baseUrl + path;
return UriComponentsBuilder.fromUriString(urlPath)
.buildAndExpand(pathParameters)
.toUri();
}
}
below is the Junit Test cases written
@RunWith(SpringRunner.class)
@DirtiesContext
@ContextConfiguration(
classes = {CircuitBreakerAutoConfiguration.class, UserService.class})
public class UserServiceFallBackTest {
private static final String USER_NAME = "userName";
private static final String PASSWORD = "password";
private static final String USERNAME_VAL = "uname";
private static final String PWD_VAL = "pwd";
private static final String userId = "test-userId";
private static final String ERROR_MESSAGE = "error message";
@Autowired
UserService userService;
@Rule
public ExpectedException thrown = ExpectedException.none();
@TestConfiguration
static class TestConfig {
@Bean
RestTemplateBuilder restTemplateBuilder() {
RestTemplateBuilder restTemplateBuilder = mock(RestTemplateBuilder.class);
RestTemplate restTemplate = mock(RestTemplate.class);
ResponseEntity responseEntity = mock(ResponseEntity.class);
when(restTemplateBuilder.build()).thenReturn(restTemplate);
when(restTemplate.exchange(
any(URI.class),
eq(HttpMethod.GET),
any(HttpEntity.class),
any(ParameterizedTypeReference.class)))
.thenThrow(new HttpServerErrorException(HttpStatus.BAD_GATEWAY));
return restTemplateBuilder;
}
@Bean(name = "userService_client_factory")
HttpComponentsClientHttpRequestFactory factory(){
HttpComponentsClientHttpRequestFactory factory = mock(HttpComponentsClientHttpRequestFactory.class);
return factory;
}
@Bean
UserService userService() {
return new UserService(restTemplateBuilder(),factory());
}
}
@Test
public void createFallbackWrapsExceptionAsServiceInvokeException() {
thrown.expect(ServiceInvokeException.class);
userService.getUser(userId);
}
@Test
public void createFallbackWrapsExceptionAsRestClientException() {
thrown.expect(UserException.class);
userService.getUser(userId);
}
}
The test case gives NullPointerException at the UserService.java class var template = restTemplateBuilder.build();
here restTemplateBuilder.build() giving null restTemaplate object