Trying to test the /health.json endpoint for the actuator for when the status is Up or DOWN.
public class ActuatorTest
{
#TestConfiguration
static class Config
{
#Bean
public HealthIndicator dbHealthIndicator()
{
return Mockito.mock(HealthIndicator.class);
}
}
#Autowired
private MockMvc mvc;
#Autowired
private HealthIndicator dbHealthIndicator;
#Test
public void healthcheck_Up() throws Exception
{
when(dbHealthIndicator.health()).thenReturn(Health.status(Status.UP).build());
mvc.perform(get("/health.json"))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.status").value("UP"));
}
#Test
public void healthcheck_Down() throws Exception
{
when(dbHealthIndicator.health()).thenReturn(Health.status(Status.DOWN).build());
mvc.perform(get("/health.json"))
.andExpect(status().isServiceUnavailable())
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8))
.andExpect(jsonPath("$.status").value("DOWN"));
}
}
the test for when the status is down always gives a status of 200 when infact it should be a 503.
Related
I am trying to write unit tests using WebTestClient in my Spring boot application.
But when tried to run, all controller test cases passed including some negative test cases.
Below is my MainApplication, Controller and ControllerTest code for your reference:
#SpringBootApplication
#EnableWebFlux
public class MyApplication {
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
}
#RunWith( SpringRunner.class )
#WebFluxTest(controllers = {MyController.class})
#AutoConfigureWebTestClient
public class MyControllerTests {
#MockBean
MyService service;
#Autowired
private WebTestClient webTestClient;
#Test
public void test() throws Exception {
webTestClient
.get()
.uri(uriBuilder ->
uriBuilder
.path("/my-controller/test")
.build())
.exchange()
.expectBody(String.class)
.equals("Hii");
}
}
#Slf4j
#RestController
#RequiredArgsConstructor
#RequestMapping("/my-controller")
public class MyController {
private final MyService myService;
#GetMapping("/test")
public String test() throws Exception {
System.out.println(">>>>>>>>>>>>>>>>>");
return "Hello :)";
}
}
You are not actually asserting whether the the response body is equal or not. Try something like this:
boolean result = webTestClient
.get()
.uri(uriBuilder -> uriBuilder.path("/my-controller/test").build())
.exchange()
.expectBody(String.class)
.equals("Hii");
Assertions.assertFalse(result); // this should pass
Currently struggling with problem when I get 'mapping error for request' with following controller/test configuration.
Controller:
#Slf4j
#Validated
#RestController
#RequiredArgsConstructor
public class AdtechController {
private final AdtechService adtechService;
#PostMapping(value = "/subscriber/session")
public ResponseEntity<ResponseDto> submitSession(#RequestBody RequestDto requestDto) {
log.trace("execute submitSession with {}", requestDto);
ResponseDtoresponse = adtechService.submitSession(requestDto);
return new ResponseEntity<>(response, HttpStatus.OK);
}
#ExceptionHandler(AdtechServiceException.class)
public ResponseEntity<AdtechErrorResponse> handleAdtechServiceException(AdtechServiceException e) {
return new ResponseEntity<>(new AdtechErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Test:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#SpringJUnitConfig({AdtechTestConfig.class})
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#Test
public void testSubmitSession() throws Exception {
RequestDto requestDto = new RequestDto ();
requestDto.setKyivstarId("1123134");
requestDto.setMsisdn("123476345242");
requestDto.setPartnerId("112432523");
requestDto.setPartnerName("125798756");
String request = OBJECT_MAPPER.writeValueAsString(requestDto);
System.out.println("REQUEST: " + request);
String response = OBJECT_MAPPER.writeValueAsString(new ResponseDto("123"));
System.out.println("RESPONSE: " + response);
mockMvc.perform(post("/subscriber/session")
.content(MediaType.APPLICATION_JSON_VALUE)
.content(request))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(containsString(response)));
}
}
Configuration:
#Configuration
public class AdtechTestConfig {
#Bean
public AdtechService adtechTestService() {
return requestDto -> new AdtechResponseDto("123");
}
}
After test execution I get No mapping for POST /subscriber/session
The reason for the struggle is that my code from other modules with the same configuration works fine. Can somebody point out what am I missing ? Thanks in advance!
Apparently you are loading a configuration class to mock beans, this interferes with the other parts of Spring Boot and probably leads to partially loading your application. I suspect only the mocked service is available.
Instead of the test configuration use #MockBean to create a mock for the service and register behaviour on it.
#SpringBootTest
#AutoConfigureMockMvc
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#MockBean
private AdtechService mockService;
#BeforeEach
public void setUp() {
when(mockService.yourMethod(any()).thenReturn(new AdtechResponseDto("123"));
}
#Test
public void testSubmitSession() throws Exception {
// Your original test method
}
}
If the only thing you want to test is your controller you might also want to consider using #WebMvcTest instead of #SpringBootTest.
#WebMvcTest(AdTechController.class)
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#MockBean
private AdtechService mockService;
#BeforeEach
public void setUp() {
when(mockService.yourMethod(any()).thenReturn(new AdtechResponseDto("123"));
}
#Test
public void testSubmitSession() throws Exception {
// Your original test method
}
}
This will load a scaled-down version of the context (only the web parts) and will be quicker to run.
try this:
#Slf4j
#Validated
#RestController
#RequiredArgsConstructor
public class AdtechController {
private AdtechService adtechService;
public AdtechController (AdtechService adtechService) {
this.adtechService= adtechService;
}
#PostMapping(value = "/subscriber/session")
public ResponseEntity<ResponseDto> submitSession(#RequestBody RequestDto requestDto) {
log.trace("execute submitSession with {}", requestDto);
ResponseDtoresponse = adtechService.submitSession(requestDto);
return new ResponseEntity<>(response, HttpStatus.OK);
}
#ExceptionHandler(AdtechServiceException.class)
public ResponseEntity<AdtechErrorResponse> handleAdtechServiceException(AdtechServiceException e) {
return new ResponseEntity<>(new AdtechErrorResponse(HttpStatus.INTERNAL_SERVER_ERROR.value(), e.getMessage()), HttpStatus.INTERNAL_SERVER_ERROR);
}
}
Test:
#RunWith(SpringRunner.class)
#SpringBootTest
#AutoConfigureMockMvc
#SpringJUnitConfig({AdtechTestConfig.class})
public class AdtechControllerTest {
private static final ObjectMapper OBJECT_MAPPER = JsonUtil.getJackson();
#Autowired
private MockMvc mockMvc;
#Autowired
private AdtechService adtechService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
this.mvc = MockMvcBuilders.standaloneSetup(new AdtechController(adtechService)).build();
}
#Test
public void testSubmitSession() throws Exception {
RequestDto requestDto = new RequestDto ();
requestDto.setKyivstarId("1123134");
requestDto.setMsisdn("123476345242");
requestDto.setPartnerId("112432523");
requestDto.setPartnerName("125798756");
String request = OBJECT_MAPPER.writeValueAsString(requestDto);
System.out.println("REQUEST: " + request);
String response = OBJECT_MAPPER.writeValueAsString(new ResponseDto("123"));
System.out.println("RESPONSE: " + response);
mockMvc.perform(post("/subscriber/session")
.content(MediaType.APPLICATION_JSON_VALUE)
.content(request))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(containsString(response)));
}
}
Is the AdtechTestConfig.class introducing the /ad-tech path segment in to your test request? If so, this is why your test is trying the path /ad-tech/subscriber/session instead of /subscriber/session.
If this is actually the correct uri, then you may add #RequestMapping to the controller like below or just to the post method itself
#Slf4j
#Validated
#RestController
#RequestMapping("/ad-tech")
#RequiredArgsConstructor
public class AdtechController {
private final AdtechService adtechService;
#PostMapping(value = "/subscriber/session")
public ResponseEntity<ResponseDto> submitSession(#RequestBody RequestDto requestDto) {
...
I have a Custom exception that handles the expected errors of my program and here is the code.
#ControllerAdvice
#RestController
public class DashboardException {
#ExceptionHandler({Exception.class, IOException.class, ParseException.class, JsonProcessingException.class})
public final ResponseEntity<ErrorDetails> dataNotFoundException(Exception ex, WebRequest request) {
ErrorDetails errorDetails = new ErrorDetails();
errorDetails.setTimestamp(new Date().toString());
errorDetails.setMessage(ex.getMessage());
errorDetails.setPath(request.getDescription(false));
errorDetails.setStatus(HttpStatus.BAD_REQUEST.value());
errorDetails.setError(HttpStatus.BAD_REQUEST);
return new ResponseEntity<>(errorDetails, HttpStatus.BAD_REQUEST);
}
}
My problem is on how to properly unit test this class. This is what I have made so far to make it cover, but with no luck.
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#ContextConfiguration(classes = { DashboardException.class, TestConfiguration.class, DataController.class })
public class testDashboardException {
private MockMvc mockMvc;
#Autowired
WebApplicationContext wac;
#Before
public void setUp() {
mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
#Configuration
#EnableWebMvc
public static class TestConfiguration { }
#Controller
#RequestMapping("/tests")
public static class RestProcessingExceptionThrowingController {
#GetMapping(value = "/exception")
public #ResponseBody String find() throws Exception {
throw new Exception("global_error_test");
}
}
#Test
public void testHandleException() throws Exception {
mockMvc.perform(get("/tests/exception"))
.andExpect(new ResultMatcher() {
#Override
public void match(MvcResult result) throws Exception {
result.getResponse().getContentAsString().contains("global_error_test");
}
})
.andExpect(status().isBadRequest());
}
/*
* #Test public void testErrorDetailsValue() {
*
* thrown.expect(Exception.class); thrown.expect(IOException.class);
* thrown.expect(ParseException.class);
* thrown.expect(JsonProcessingException.class);
*
* thrown.expectMessage("Bad Request");
*
* }
*/
}
I only have a little knowledge concerning custom exceptions. What am I missing here? Thanks for any assistance.
I found out how to cover my custom exception. I just included a test on my controller that will fail the endpoint and it did catch an exception and covered my custom exception.
I am getting assertion error saying it's getting 406 and expected 200. Not sure how to fix this. For your info i am trying to upgrade spring boot 1.5.2 to 2.1.4
Below is my code -
#ContextConfiguration(classes = ChangeController.class)
#WebAppConfiguration
public class ChangeControllerTest extends AbstractJUnit4SpringContextTests {
private MockMvc mockMvc;
#Autowired
private WebApplicationContext wac;
#Before
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac).build();
}
#Test
public void verifyInvalidToDoArgument() throws Exception {
mockMvc.perform(MockMvcRequestBuilders.get("/log").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andDo(print());
}
}
Controller class
#Controller
#RequestMapping("/log")
public class ChangeController {
#ApiIgnore
#RequestMapping(method = RequestMethod.GET, produces = {"text/plain"})
public
#ResponseBody
String generate() {
return "some string is here
";
}
}
Below is console response-
java.lang.AssertionError: Status
Expected :200
Actual :406
I have declared an interface as a property of my #RestController. That interface just has a few fields/setters/getters.
The implementation of the RestController and GetMapping look like this:
#RestController
#EnableAutoConfiguration
public class AccountController {
private AccountStoreInterface store;
#GetMapping(value="/account")
public Account readAccount(#RequestParam("id") String id) throws AccountNotFoundException {
Account a = store.getAccount(id);
if (a.getId().isEmpty()) {
throw new AccountNotFoundException();
}
return a;
}
#ExceptionHandler(AccountNotFoundException.class)
#ResponseStatus(NOT_FOUND)
public #ResponseBody String handleAccountNotFoundException(AccountNotFoundException ex) {
return ex.getMessage(); }
#ExceptionHandler(NullPointerException.class)
#ResponseStatus(INTERNAL_SERVER_ERROR)
public #ResponseBody String handleNullPointerException(NullPointerException ex) {
return ex.getMessage();
}
}
The interface declaration looks like this:
public interface AccountStoreInterface {
public Account getAccount(String id) throws AccountNotFoundException;
public Account setAccount(String id, Account account) throws AccountConflictException;
}
I would like to test this using spring-boot-starter-test and junit4. I expect the following test to return a 500 because I have not passed any store object that implements my interface so it should throw a NullPointerException.
How do I configure my unit tests in order to test the 500 and 404 status codes?
Right now, the below test actually fails because the returned status is 200, which I don't understand how junit gets to.
#RunWith(SpringRunner.class)
#WebMvcTest(AccountController.class)
public class TestAccountController {
#Autowired private MockMvc mockMvc;
#Autowired private WebApplicationContext wac;
#MockBean
private AccountController accountController;
#Test
public void testGetAccountNotFound() throws Exception {
mockMvc.perform(get("/account?id={id}", "test-account-id-123")
.accept(APPLICATION_JSON)
.characterEncoding("UTF-8"))
.andDo(print())
.andExpect(status().isNotFound());
}
}