spring tests with mocks and HttpMessageConversionException - spring

i have something like that in my ParkingServiceController.
#PostMapping("/departure")
public ResponseEntity<String> departure(#RequestBody CarAtGateModel carAtGateModel) throws UnidentifiedCarException {
CarAndParkingEntity carAndParkingEntity = carsAndParkingsRepository.findByIdCar(
carAtGateModel.getCarEntity().getIdCar()).orElseThrow(() -> new UnidentifiedCarException());
carAndParkingEntity.setIdParking("-1");
carsAndParkingsRepository.flush();
return new ResponseEntity<>(responsesMessages.gateUp(), HttpStatus.OK);
}
and next i wanted to do test with some mocks.
#Test
public void testArrivalWhenParkingIdNotExists() {
//given
CarAndParkingEntity carAndParkingEntity = mock(CarAndParkingEntity.class);
carAtGateModel = mock(CarAtGateModel.class);
//when
when(carsAndParkingsRepository.findByIdCar(anyString())).thenReturn(Optional.of(carAndParkingEntity));
HttpEntity<CarAtGateModel> request = new HttpEntity<>(carAtGateModel);
ResponseEntity response = testRestTemplate.postForEntity("/departure", request, String.class);
//then
assertEquals("Parking with that id does not exists", response.getBody());
}
but i'm getting that exception every time with every code change in test
org.springframework.http.converter.HttpMessageConversionException: Type definition error: [simple type, class org.mockito.internal.creation.bytebuddy.ByteBuddyCrossClassLoaderSerializationSupport]; nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException: No serializer found for class org.mockito.internal.creation.bytebuddy.ByteBuddyCrossClassLoaderSerializationSupport and no properties discovered to create BeanSerializer (to avoid exception, disable SerializationFeature.FAIL_ON_EMPTY_BEANS) (through reference chain: com.example.parkingservice.models.CarAtGateModel$MockitoMock$1316802841["mockitoInterceptor"]->org.mockito.internal.creation.bytebuddy.MockMethodInterceptor["serializationSupport"])
When i'm not using any mock test passess correctly so imo i'm doing something wrong with mocking

At first sight, as your ParkingServiceController has a composition with CarsAndParkingRepository, you should mock that dependency first. I don't know why you are mocking carAtGateModel, you can use a real object representing the the data you want to pass to the controller (the same applies to carAndParkingEntity).
It would be helpful if you add more details, explaining what you want to test because it's not totally clear the assertion you are doing.

Related

spring why mocked method throws exception when optional exists

i have endpoint like this:
#PostMapping("/departure")
public ResponseEntity<String> departure(#RequestBody CarAtGateModel carAtGateModel) throws UnidentifiedCarException {
CarAndParkingEntity carAndParkingEntity = carsAndParkingsRepository.findByIdCar(
carAtGateModel.getCarEntity().getIdCar()).orElseThrow(() -> new UnidentifiedCarException());
carAndParkingEntity.setIdParking("-1");
carsAndParkingsRepository.flush();
return new ResponseEntity<>(responsesMessages.gateUp(), HttpStatus.OK);
}
and next i wanted to do some tests with mocks like:
#Test
public void departureWorksWhenCarOnDepartureIsRecognized() {
//given
carsAndParkingsRepository = mock(CarsAndParkingsRepository.class);
CarAndParkingEntity carAndParkingEntity = new CarAndParkingEntity();
CarAtGateModel carAtGateModel = new CarAtGateModel();
CarEntity carEntity = new CarEntity();
carEntity.setIdCar("-1");
carEntity.setProducer("a");
carEntity.setModel("b");
carEntity.setWidth(1.6);
carEntity.setPowerType(PowerType.PB);
carAtGateModel.setCarEntity(carEntity);
carAtGateModel.setParkingId("parkingId");
//when
when(carsAndParkingsRepository.findByIdCar(carEntity.getIdCar())).thenReturn(Optional.of(carAndParkingEntity));
HttpEntity<CarAtGateModel> request = new HttpEntity<>(carAtGateModel);
ResponseEntity<String> response = testRestTemplate.postForEntity("/departure", request, String.class);
//then
assertEquals(200, response.getStatusCodeValue());
}
Mocking repository for return optional works correctly, it returns carAndParkingEntity.
But test doesn't pass becouse it throws UnidentifiedCarException and I can't understand why I'm getting exception when carsAndParkingsRepository.findByIdCar(carEntity.getIdCar()) returns optional, so it should exist...
You are providing lack of code to indentify problem correctly. From what i see, your mocked repository is nowhere injected into the controller. So you can not expect repository in controller to behave in a way you declared in your test.
Here is an example of how to test web layer in Spring https://spring.io/guides/gs/testing-web/
Tip: you shouldn't use repository nor business logic in your web layer. It is just terrible practice. Separate all logic into separate layer and mock that instead. Then you can make separate unit tests just for your logic. Testing your web layer shouldn't include testing of your repository access or business logic

How to check Bad request for #Min on request param in spring controller?

I am pretty new to spring controller. I am trying to write unit test for invalid parameter. I have an api that has #RequestParam("id") #Min(1) long id and in my unit test, I pass in "-1". Here is my test:
#Test
public void searchWithInvalidIbId() throws Exception {
mockMvc.perform(get(BASE_URL)
.param(COLUMN_IB_ID, INVALID_IB_ID_VALUE) // = "-1"
.param(COLUMN_TIME_RANGE, TIME_RANGE_VALUE)
.param(COLUMN_TIME_ZONE, TIME_ZONE_VALUE)
.accept(PowerShareMediaType.PSH_DISPATCH_REPORTER_V1_JSON)
.contentType(PowerShareMediaType.PSH_DISPATCH_REPORTER_V1_JSON))
.andExpect(status().isBadRequest());
}
When I run this, I get
org.springframework.web.util.NestedServletException: Request processing failed; nested exception is javax.validation.ConstraintViolationException: search.arg2: must be greater than or equal to 1
It makes sense, but I am not sure how to test this is BadRequest. I tried #Test(expected = NestedServletException.class), and it passed, but I don't think it is checking what I want to check. What is the right approach to check this?
You can have your custom exception handler annotated with #ControllerAdvice and handle ConstraintViolationException in that class. You can throw your custom exception with additional details if you wish.
Here is an example approach:
#ControllerAdvice
public class MyCustomExceptionHandler {
#ResponseBody
#ResponseStatus(HttpStatus.BAD_REQUEST)
#ExceptionHandler(ConstraintViolationException.class)
ApiError constraintViolationException(ConstraintViolationException e) {
return BAD_REQUEST.apply(e.getBindingResult());
}
}
Here ApiError is a custom class to represent your error response, it can be anything else you want. You can add timestamp, http status, your error message etc.

spring boot unit testing using testng

How to write a POST method test case if the return type of a particular create method in the service layer is ResponseEntity<Object>?
This is my createOffer method:
public ResponseEntity<Object> createOffer(Offer offer) {
Offer uoffer = offerRepository.save(offer);
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{jobTitle}").
buildAndExpand(uoffer.getJobTitle()).toUri();
return ResponseEntity.created(location).build();
}
and this is its corresponding test class method:
#Test
public void testCreateOffer() {
Offer offer = new Offer("SE",new Date(),5);
Mockito.when( offerRepository.save(offer)).thenReturn( offer);
assertThat(offerServiceImpl.createOffer(offer)).isEqualTo(offer);
}
Here I am getting an error while running this test case which is no current servlet request attributes and exception is:
java.lang.IllegalStateException
Why is it coming
This answers the above question.
Hope it helps when someone finds the same issue !!!
#Test
public void testCreateOffer() {
Offer offer = new Offer("SE",new Date(),5);
MockHttpServletRequest request = new MockHttpServletRequest();
RequestContextHolder.setRequestAttributes(new ServletRequestAttributes(request));
URI location = ServletUriComponentsBuilder.fromCurrentRequest().path("/{jobTitle}").
buildAndExpand(offer.getJobTitle()).toUri();
ResponseEntity<Object> response = ResponseEntity.created(location).build();
Mockito.when( offerRepository.save(offer)).thenReturn(offer);
assertThat( offerServiceImpl.createOffer(offer)).isEqualTo(response);
}
Problem is that in your method you want to get infromation from class ServletUriComponentsBuilder. When you open this class in comment is
UriComponentsBuilder with additional static factory methods to create
links based on the current HttpServletRequest.
So it means when your application is running on server (e.g. tomcat) you have context and you can read information from HttpServletRequest. But in junit you don't have context and you can't get this iformation. So when your code is runnig and reach the ServletUriComponentsBuilder.fromCurrentRequest() then the code is done. So you have to mock it. Look at this link it can help you.
ServletUriComponentsBuilderTests
Kotlin.
I was getting java.lang.IllegalStateException: No current ServletRequestAttributes cause I had this line in my service:
val location = ServletUriComponentsBuilder.fromCurrentRequest().build().toUri()
I have put the following into my setUp() function:
#BeforeEach
fun setup() {
MockitoAnnotations.openMocks(this)
val request = MockHttpServletRequest()
RequestContextHolder.setRequestAttributes(ServletRequestAttributes(request))
}

spring mockMVC testing method GET

i created post method in mockMVC (in spring boot project)
This is my method testing
This is my method testing
#Test
public void createAccount() throws Exception {
AccountDTO accountDTO = new AccountDTO("SAVINGS", "SAVINGS");
when(addaccountService.findByName("SAVING")).thenReturn(Optional.empty());
when(addaccountService.createAccount(any())).thenReturn(createdAccountDTO);
CreatedAccountDTO createdAccountDTO = new CreatedAccountDTO("a#wp.pl", "SAVINGS", "1234rds", uuid);
mockMvc.perform(
post("/account").contentType(MediaType.APPLICATION_JSON)
.content(asJsonString(AccountNewDTO)))
.andExpect(status().isCreated())
.andExpect(header().string("location", containsString("/account/"+uuid.toString())));
System.out.println("aaa");
}
I want to write GET method.
how to write a get method in mock mvc? how to verify whether what I threw was returned?
You can try the below for Mockmvc perform get and post methods
For get method
#Autowired
private MuffinRepository muffinRepository;
#Test
public void testgetMethod throws Exception(){
Muffin muffin = new Muffin("Butterscotch");
muffin.setId(1L);
BddMockito.given(muffinRepository.findOne(1L)).
willReturn(muffin);
mockMvc.perform(MockMvcRequestBuilders.
get("/muffins/1")).
andExpect(MockMvcResutMatchers.status().isOk()).
andExpect(MockMvcResutMatchers.content().string("{\"id\":1, "flavor":"Butterscotch"}"));
}
//Test to do post operation
#Test
public void testgetMethod throws Exception(){
Muffin muffin = new Muffin("Butterscotch");
muffin.setId(1L);
BddMockito.given(muffinRepository.findOne(1L)).
willReturn(muffin);
mockMvc.perform(MockMvcRequestBuilders.
post("/muffins")
.content(convertObjectToJsonString(muffin))
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON))
.andExpect(MockMvcResutMatchers.status().isCreated())
.andExpect(MockMvcResutMatchers.content().json(convertObjectToJsonString(muffin)));
}
If the response is empty then make sure to override equals() and hashCode() method on the Entity your repository is working with
//Converts Object to Json String
private String convertObjectToJsonString(Muffin muffin) throws JsonProcessingException{
ObjectWriter writer = new ObjectWriter().writer().withDefaultPrettyPrinter();
return writer.writeValueAsString(muffin);
}
You can use the static get method of the class MockMvcRequestBuilders, see: https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/test/web/servlet/request/MockMvcRequestBuilders.html#get-java.lang.String-java.lang.Object...-
Example:
mockMvc.perform(get("/account")).andExpect(...);
If you throw an exception within your controller method it will typically trigger execution of an exception handler which transforms the exception into a HTTP error response. By default, you could check if the status of the response was 500. If you have implemented your own exception handler you may want to check the response body as well to verify if it contains the expected error data.

How to check returntype in Spring Unittest using MockMVC?

The Spring method I wanna test
#RequestMapping(value="/files", method=RequestMethod.GET)
#ResponseBody
public List<FileListRequest> get() {
return getMainController().getAllFiles();
}
I want to be assured all calls to /files are responded with an List[FileListRequest]. How?
This is the method in which the test is supposed to be.
#Test
public void testGetAll() throws Exception {
this.mockMvc.perform(get("/files").accept("application/json"))
.andExpect(status().isOk())
.andExpect(content().contentType(SOMETHING);
}
Can I simply replace the SOMETHING or am I totally wrong?
Can I run assert methods on the object returned by perform()?
Edit:
MvcResult result = this.mockMvc.perform(get("/files").accept("application/json"))
.andExpect(status().isOk())
.andReturn();
String content = result.getResponse().getContentAsString();
// Convert json String to Respective object by using Gson or Jackson
ObjectMapper mapper = new ObjectMapper();
TypeFactory typeFactory=objectMapper.getTypeFactory();
List<SomeClass> someClassList =mapper.readValue(content , typeFactory.constructCollectionType(List.class, SomeClass.class));
//Assert here with your list
You could use Json Path to check if specific data exist in your response
a code snipper from by old project
mockMvc.perform(get("/rest/blogs")) .contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.blogs[*].title",
hasItems(endsWith("Title A"), endsWith("Title B"))))
.andExpect(status().isOk());
You cannot use contentType to check the class of instances. The Content-Type is to determine the format of text sent/returned in a HTTP(S) request/response, and has nothing to do with programmatic type-check. It only regulates that the request/response is in json/text-plain/xml, etc.
To check the type of the objects returned in the response, let's assume that the response is in format JSON(built-in Jackson in Spring boot will do the (un)marshalling), and we just use org.hamcrest.Matchers.instanceOf(Class<?> type) to check the class of first item in the list, with jsonPath.
A working snippet:
import static org.hamcrest.Matchers.instanceOf;
...
#Test
public void testBinInfoControllerInsertBIN() throws Exception {
when(this.repository.save(mockBinInfo)).thenReturn(mockBinInfo);
this.mockMvc.perform(post("/insert")
.content("{\"id\":\"42\", \"bin\":\"touhou\", \"json_full\":\"{is_json:true}\", \"createAt\":\"18/08/2018\"}")
.accept(MediaType.APPLICATION_JSON_UTF8_VALUE)
.contentType(MediaType.APPLICATION_JSON_UTF8_VALUE)
)
.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8_VALUE))
.andExpect(status().isCreated())
.andExpect(jsonPath("$[0]", instanceOf(BinInfo.class)))
.andExpect(jsonPath("$[0].bin", is("touhou")));
}
If you want to check every item in the list... maybe it is redundant? I haven't seen code examining each and every item in the list because you have to iterate. There is way, of course.

Resources