How to throw a JsonProcessingException with mockito - java

i have this lines in my code:
#Autowired
private ObjectMapper mapper = new ObjectMapper();
#PostMapping("/postPrueba")
public ResponseEntity<String> postPrueba(#RequestBody Prueba prueba) {
String pTest = null;
try {
pTest = mapper.writeValueAsString(prueba);
System.out.println(pTest );
} catch (JsonProcessingException e) {
return new ResponseEntity<>("", HttpStatus.INTERNAL_SERVER_ERROR);
}
return new ResponseEntity<>("", HttpStatus.OK);
}
My model Prueba.java
public class Prueba {
#Id
private String nombre;
private String apellidos;
private String edad;
}
And in test i want to force the JsonProcessingException but i canĀ“t. I already try this:
#Mock
private ObjectMapper mapperMock;
#Test
public void testKo() throws Exception {
ObjectMapper om = Mockito.spy(new ObjectMapper());
Mockito.when(this.mapperMock.writeValueAsString(Mockito.any())).thenThrow(new JsonProcessingException("") {});
ObjectMapper om = Mockito.spy(new ObjectMapper());
Mockito.when( om.writeValueAsString(Mockito.eq(Prueba.class))).thenThrow(new JsonProcessingException("") {});
Mockito.when(this.mapperMock.writeValueAsString(Mockito.eq(Prueba.class))).thenThrow(new JsonProcessingException("") {});
String jsonContent = "{'nombre': '123456', 'apellidos': '12'}";
jsonContent = jsonContent.replaceAll("\'", "\"");
this.mvc.perform(post("/postPrueba")
.contentType(MediaType.APPLICATION_JSON)
.content(jsonContent))
.andExpect(status().is5xxServerError());
}
But always the response is a 200 OK. How can i do this?

doThrow(JsonProcessingException.class).when(object).method(...);

You'll need to mock your http behaviour because the ObjectMapper is out of the scope. Found WireMock fits your purpose in terms of filtering http traffic and mocking responses

Rather then throwing JsonProcessingException from test just make ObjectMapper actually throw that exception with some false data to process.

You need to replace the Bean in the spring context.
I assume you use Spring Boot with #RunWith(SpringRunner.class) and #WebMVCTest?
Then you can do this using #MockBean
See also: https://www.baeldung.com/java-spring-mockito-mock-mockbean

Try this:
Mockito.doThrow(JsonProcessingException.class).when(this.mapperMock).writeValueAsString(Mockito.any());

Related

Assertion error expected 500 but got 400 Junit testing

Controller:
#ApiOperation(value = " update record", response = APIResponse.class)
#ApiResponses(value = {#ApiResponse(code =200, message = "OK"),
#ApiResponses(value = {#ApiResponse(code =500, message = "Internal server error"),
#ApiResponses(value = {#ApiResponse(code =404, message = "NO_RECORD")})
#PutMapping(value = "/update/{id}")
#ResponseBody
public ResponseEntity<APIResponse> updateRecord(HttpServletRequest request, #RequestBody RecordDTO input, #PathVariable(value="id") int code){
APIResponse response = null;
try{
response = service.updateRecord(code, input);
}
catch(JSONException e){
log.error("Error Parsing JSON");
response = new APIResponse(HttpStatus.INTERNAL_SERVER_ERROR, ERROR_JSON_PARSING, ERROR);
}
return new ResponseEntity<>(response, HttpStatus.OK);
}
my test case foor controller:
#Test
public void update() throws Exception{
RecordDTO recordDto = new RecordDTO();
Object mapper = new ObjectMapper();
String value = mapper.writeValueAsString(StationDTO);
given(service.updateRecord(anyInt(), any(RecordDTO.class))).willThrow(JSONException.class);
mockMvc.perform(put(baseUrl + "/update/12")
.contentType(MediaType.APPLICATION_JSON).content(value))
.andExpect(status().isInternalservererror())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.status",Matchers.is("INTERNAL_SERVER_ERROR")))
.andExpect(jsonPath("$.message",Matchers.is("ERROR_JSON_PARSING")))
.andExpect(jsonPath("$.resposeStatus",Matchers.is("ERROR")));
APIResponse response = new APIResponse(HttpStatus.OK, SUCCESS, SUCCESS, null);
given(service.updateRecord(anyInt(), any(RecordDTO.class))).willReturn(response);
mockMvc.perform(put(baseUrl + "/update/12")
.contentType(MediaType.APPLICATION_JSON).content(value))
.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
.andExpect(jsonPath("$.status",Matchers.is("OK")))
.andExpect(jsonPath("$.message",Matchers.is("SUCCESS")))
.andExpect(jsonPath("$.resposeStatus",Matchers.is("SUCCESS")));
}
DTO:
public class RecordDTO{
private String id;
private String name;
private String number;
}
I am getting java.lang assertion error expected 500 but was 200. I don't what is wrong with the test case.. Is there any other way to write the test case? Also can you recommend any platform from where i can gain knowledge of how to write test cases then do comment down. Thanks for the help!
Seems like your mocked service is not injecting into your controller.
Alternative solution (I assume you use Spring-Boot):
DisableAutowireRequireInitializer. This will prevent to load all dependencies inside your Controller.
Create inside your ControllerTest inner class: private static ServiceImplMock entends ServiceImpl
Now, override updateRecord method inside ServiceMock to do your testing cases
#Override
public APIResponse updateRecord(int code, RecordDTO input) throws JSONException {
if(code == 12) throw new JSONException(...)
else your_business_logic
}
Now, add this ServiceImplMock into your #SpringBootTest
#SpringBootTest(classes = {
Controller.class,
ControllerTest.ServiceImplMock.class,
...
})
#AutoConfigureMockMvc
#ContextConfiguration( initializers = {DisableAutowireRequireInitializer.class })
class ControllerTest {
Now, your test cases should work (Remove given(...).willThrow(...); since we don't need it anymore)
Also can you recommend any platform from where i can gain knowledge of how to write test cases then do comment down
https://www.baeldung.com/junit
https://www.baeldung.com/spring-boot-testing
https://mkyong.com/spring-boot/spring-boot-junit-5-mockito/

How to do Mockito unit test on method which has a return value ResponseEntity<byte[]>?

I'm new to testing and Mockito. However, not so new in working Spring.
I have a service layer implementation of exportResource(String id, String fileType, Class resourceClass) throws MyCustomEx1, MyCustomEx2. My assignment is to create a unit test with Mockito for exportResource() which is downloading a file directly from browser or throws exception if for some reason reaching to ResponseEntity return statement is not successfull.
Here is a rough overview of a service layer class where exportResource() is living;
#Service
#AllArgsConstructor
public class ExportImportServiceImpl implements ExportImportService {
private final FhirRepository fhirRepository;
private final CtsConfig ctsConfig;
#Override
public ResponseEntity<byte[]> exportResource(String id, String fileType, Class resourceClass) throws throws MyCustomEx1, MyCustomEx2 {
if (fileType == null ) throw new MyCustomEx1();
Bundle bundle = (Bundle) fhirRepository.resourcesWithCriterion(resourceClass, DaoConstants.ID, null).get();
if (bundle != null && bundle.hasEntry()) {
Optional<Bundle.BundleEntryComponent> resource =
bundle.getEntry()
.stream()
.filter(filter -> resourceClass.isInstance(filter.getResource()))
.findFirst();
if (resource.isPresent()) {
IBaseResource castedResource = (IBaseResource) resourceClass.cast(resource.get().getResource());
IParser parser = null;
MediaType mt = null;
if (fileType.equalsIgnoreCase("json")){
mt = MediaType.APPLICATION_JSON;
parser = fhirRepository.jsonParser();
} else if (fileType.equalsIgnoreCase("xml")){
mt = MediaType.APPLICATION_XML;
parser = fhirRepository.xmlParser();
} else throw new MyCustomEx1();
parser.setPrettyPrint(true);
var serializedResource = parser.encodeResourceToString(castedResource);
return ResponseEntity
.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,"attachment;" + "filename=" + resourceClass.getSimpleName() + "-" + castedResource.getId() + "." + fileType)
.contentType(mt)
.contentLength(serializedResource.getBytes(StandardCharsets.UTF_8).length)
.body(serializedResource.getBytes(StandardCharsets.UTF_8));
}
}
throw new MyCustomEx2();
}
//other implementations here...
}
I do understand (by wastching some tutorials etc) that we can use Mockito to mock external services/repositories, to verify if some method is getting called, to mock some return values etc. But I'm confused about if-else parts in my business logic-code. Namely, the part:
if (bundle != null && bundle.hasEntry()) {
Optional<Bundle.BundleEntryComponent> resource =
bundle.getEntry()
.stream()
.filter(filter -> resourceClass.isInstance(filter.getResource()))
.findFirst();
if (resource.isPresent()) {
IBaseResource castedResource = (IBaseResource) resourceClass.cast(resource.get().getResource());
IParser parser = null;
MediaType mt = null;
if (fileType.equalsIgnoreCase("json")){
mt = MediaType.APPLICATION_JSON;
parser = fhirRepository.jsonParser();
} else if (fileType.equalsIgnoreCase("xml")){
mt = MediaType.APPLICATION_XML;
parser = fhirRepository.xmlParser();
} else throw new ByException(ByErrorCode.ERR_BY_1013);
parser.setPrettyPrint(true);
var serializedResource = parser.encodeResourceToString(castedResource);
I don't understand how to write test to handle if-else part. I mean, isn't too simple to test something like that?
Here is what I (sadly) got:
#Test
void exportCodeSystem() throws Exception {
String id = "32";
verify(this.fhirRepository.resourcesWithCriterion(ValueSet.class, DaoConstants.ID, null));
Mockito.when(
controller.exportCodeSystem(Mockito.anyString(),Mockito.anyString())
).thenReturn(ResponseEntity.ok().contentType(MediaType.APPLICATION_JSON).build());
RequestBuilder request = MockMvcRequestBuilders.get("/url-to-controller")
.param("id","32")
.param("file-type", "json");
MvcResult result = mockMvc.perform(request).andReturn();
Assertions.assertFalse(result.getResponse().getStatus() == 200);
}
This throws some error. But that is not important as to how to write meaningful unit test in this case? Or even better, how to write code which can be easily unit-tested?
UPDATE 1
This is how my test looks now:
#Test
void exportCodeSystem() throws Exception {
CompletableFuture<Bundle> completedFuture = CompletableFuture.completedFuture(this.codeSystemBundle);
Mockito.when(this.fhirRepository.resourcesWithCriterion(ArgumentMatchers.<Class<CodeSystem>>any(),
ArgumentMatchers.<ICriterion<? extends IParam>>any(),
eq(null)))
.thenReturn(completedFuture);
MvcResult result = mockMvc.perform(MockMvcRequestBuilders.
get("/code-system/export")
.param("id", "32").param("file-type", "json"))
.andExpect(MockMvcResultMatchers.status().isOk())
.andExpect(MockMvcResultMatchers.content().contentType("application/json")).andReturn();
Assertions.assertEquals(result.getResponse().getStatus(), HttpStatus.OK.value());
}
I keep getting NPE on the line where MvcResult result .. is. What I want to achive with test? I don't know to be honest. I'm trying to test in a some meaningful way, but I don't think I understand how to achieve that.
This is how controller looks like:
#AllArgsConstructor
#RestController
#RequestMapping("/code-system")
public class CodeSystemController {
private final ExportImportService exportImportService;
#GetMapping("/export")
public boolean exportCodeSystem(#RequestParam("id") String id, #RequestParam("file-type") String fileType) throws IOException, ByException{
return this.exportImportService.exportResource(id, fileType, CodeSystem.class);
}
}
What do you want to test? Would your test be unit test or integration test? Which bean do you want to unit test - controller or the service?
If you want to test the controller via mockMvc you can do this:
#Autowired
private MockMvc mockMvc;
#Autowired
ExportImportService exportImportService;
#Test
public void yourTest() throws Exception {
byte[] expectedBytes = ...;
when(exportImportService.exportResource(id, fileType, CodeSystem.class)).thenReturn(ResourceEntity.ok(expectedBytes ));
mockMvc.perform(post("/code-system/export").param("id", "id").param("file-type", "json")).andExpect(content().bytes(expectedBytes ));
verify(exportImportService).exportResource("id", "json", CodeSystem.class);
}
Or if you want to write an integration test you should mock the repo instead of the service:
#MockBean
FhirRepository fhirRepository
#MockBean // or #Mock, #Spy, #SpyBean depends on your fhirRepository implementation.
IParser parser;
#Test
public void yourTest() throws Exception {
byte[] expectedBytes = ...;
Bundle bundle = ...;
when(fhirRepository.resourcesWithCriterion(Mockito.any(), Mockito.any(), Mockito.any()).thenReturn(bundle)
when(fhirRepository.jsonParser()).thenReturn(parser);
when(parser.encodeResourceToString(Mockito.any())).thenReturn(new String(expectedBytes));
mockMvc.perform(post("/code-system/export").param("id", "id").param("file-type", "json")).andExpect(content().bytes(expectedBytes));
}

Mockito "thenThrow" doesn't throw the exception when expected

I have an issue when trying to test a class that represents a Rest Client. I'm using RestTemplate in Spring Boot.
This is the abstract 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());
}
...
}
}
This is the actual implementation:
public class ActualRestClient extends RestClient {
public RestResponse sendFetchFileRequest(URI baseUri, FetchFileRequest request) throws ServerException, ClientException {
return sendPostRequest(baseUri, "FETCH_FILE", request, RestResponse.class);
}
}
An this is the test:
#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 and ServerException are exceptions created by me by extending Exception class.
My problem is that in the RestClient class another Exception is catched(message:"URI is not absolute") instead of HttpServerErrorException and I can't understand why. Thank you!
As the commenter already expressed: doing new URI("something") already throws at you. But even when you pass a "valid" URI, your code will not work, as there is a misconception on your end. You see:
RestTemplate restTemplate = new RestTemplate();
response = restTemplate.exchange(baseUri, HttpMethod.POST, getEntity(restRequest), responseClass);
That code lives within a method of your class under test. But #InjectMocks works only for fields of classes.
In other words: when your production code gets executed, a new (completely different** ResponseTemplate instance is created. And therefore your mocking spec is irrelevant, because the method isn't invoked on your mock in the first place.
Two choices:
turn that local variable into a field of your class under test (then injecting should work)
or, as you are already using PowerMock(ito), you could use that mocking framework to intercept that call to new().
I suggest you rather use option one, and avoid to use the PowerMock(ito) extension altogether!

Can't manage to test rest template helper class

I'm trying for more than an hour to test this class. It went so ugly of stubbing the whole components of the method etc. I'd love some advice how to make a better test or refactor the class to make it way easier to test. I could not figure out a way yet.
Class to Test
#Slf4j
public final class HistoryRestService {
static RestTemplate restTemplate = new RestTemplate();
public static Optional<List<History>> findLatestHistories() {
String url = buildUrl();
ResponseEntity<History[]> responseEntity = null;
try {
responseEntity = restTemplate.getForEntity(url, History[].class);
} catch (ResourceAccessException e) {
log.warn("No connection to History persistence. Please check if the history persistence started up properly");
return Optional.empty();
}
History[] histories = responseEntity.getBody();
return Optional.of(Arrays.asList(histories));
}
private static String buildUrl() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("http://");
stringBuilder.append("localhost");
stringBuilder.append(":8081");
stringBuilder.append("/history/get");
return stringBuilder.toString();
}
// For Testing
static void setRestTemplate(RestTemplate restTemplate) {
HistoryRestService.restTemplate = restTemplate;
}
}
Spock Test which fails
class HistoryRestServiceTest extends Specification {
def "test findLatestHistories"() {
given:
History mockedHistory = Mock()
HistoryRestService uut = new HistoryRestService()
History[] expected = [mockedHistory]
RestTemplate mockedRestTemplate = Stub()
ResponseEntity<History> mockedResponseEntity = Stub()
mockedResponseEntity.getBody() >> expected
mockedRestTemplate.getForEntity(_) >> mockedResponseEntity
uut.setRestTemplate(mockedRestTemplate)
when:
def actual = uut.findLatestHistories()
then:
actual.get() == expected
}
}
I'd suggest using real depedency-injection (spring/guice/cdi) instead of static variables.
Furthermore, you should think about what you want to test, is it the correct request and parsing of the network call, then write an integration test using something like mockserver or wiremock to have the whole stack. Or, if you are just concerned with the result handling, then you could move the code that interacts with RestTemplate into a separate method and use partial mocking to mock this method. I'd suggest to use the real integration test, but for the sake of an example this should work, but I didn't verify the code.
#Slf4j
public class HistoryRestService {
private final RestTemplate restTemplate;
public HistoryRestService() {
restTemplate = new RestTemplate();
}
public HistoryRestService(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public Optional<List<History>> findLatestHistories() {
try {
return Optional.of(Arrays.asList(getLatestHistories(buildUrl())));
} catch (ResourceAccessException e) {
log.warn("No connection to History persistence. Please check if the history persistence started up properly");
return Optional.empty();
}
}
History[] getLatestHistories(String url) throws {
ResponseEntity<History[]> responseEntity = null;
responseEntity = restTemplate.getForEntity(url, History[].class);
return responseEntity.getBody()
}
private String buildUrl() {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("http://");
stringBuilder.append("localhost");
stringBuilder.append(":8081");
stringBuilder.append("/history/get");
return stringBuilder.toString();
}
}
class HistoryRestServiceTest extends Specification {
#Subject
HistoryRestService uut = Spy()
def "test findLatestHistories"() {
given:
History[] expected = [mockedHistory]
when:
def actual = uut.findLatestHistories()
then:
actual.get() == expected
1 * uut.getLatestHistories(_ as String) >> expected
}
def "test findLatestHistories returns empty on exceptions"() {
given:
History[] expected = [mockedHistory]
when:
def actual = uut.findLatestHistories()
then:
!actual.present
1 * uut.getLatestHistories(_ as String) >> {throw new ResourceAccessException()}
}
}

Parsing GET JSON reply without keys to object in Spring

I am currently consuming content in the style of
"potter",["potter harry","potter","potter hallows 2","potter collection","potter hallows 1","potter dvd box","potter 7","potter hallows","potter blue ray","potter feniks"],[{"xcats":[{"name":"dvd_all"},{"name":"books_nl"}]},{},{},{},{},{},{},{},{},{}],[]]
Using the following code in Spring
RestTemplate restTemplate = new RestTemplate();
String information = restTemplate.getForObject(URL, String.class);
//further parsing of information, using String utilities
Obviously this is not the way to go, because I should be able to automatically parse it somehow. I will also only need the content of the second element as well (the array, from potter harry to potter feniks).
What is the best way to parse a GET response like that, when its json contents aren't name-valued?
#Test
public void testJson(){
RestTemplate template = new RestTemplate();
ResponseEntity<ArrayNode> entity = template.
exchange("https://api.myjson.com/bins/2rl7m", HttpMethod.GET, null, new ParameterizedTypeReference<ArrayNode>() {
});
ArrayNode body = entity.getBody();
body.get(1).forEach(m->{
System.out.println(m.asText());});
}
But my advice is if you can change the response type not to be json array with mixed value types in it will be better
The following helper class enabled me to easily parse the response and get the list I needed
public class JSONHelper {
private static final JsonFactory factory = new JsonFactory();
private static final ObjectMapper mapper = new ObjectMapper(factory);
public static List<String> getListOnPosition(int i, String inputWithFullList) throws JsonProcessingException, IOException {
List<String> result = new ArrayList<String>();
JsonNode rootNode = mapper.readTree(inputWithFullList);
ArrayNode node = (ArrayNode) rootNode.get(i);
if (!node.isArray()) {
result.add(node.asText());
} else {
for (final JsonNode subNode : node) {
result.add(subNode.asText());
}
}
return result;
}
}
Some JUnit tests for this scenario
public class JSONHelperTest {
#Test
public void parseListOnPositionFullListTest() throws JsonProcessingException, IOException {
String inputWithFullList = "[\"a\",[\"b\", \"c\", \"d\"],[],[]]";
List<String> result = JSONHelper.getListOnPosition(1, inputWithFullList);
assertEquals(3, result.size());
assertEquals(Arrays.asList("b", "c", "d"), result);
}
#Test
public void parseListOnPositionOneElementListTest() throws JsonProcessingException, IOException {
String inputWithFullList = "[\"a\",[\"b\"],[],[]]";
List<String> result = JSONHelper.getListOnPosition(1, inputWithFullList);
assertEquals(1, result.size());
assertEquals(Arrays.asList("b"), result);
}
#Test
public void parseListOnPositionEmptyListTest() throws JsonProcessingException, IOException {
String inputWithFullList = "[\"a\",[],[],[]]";
assertTrue(JSONHelper.getListOnPosition(1, inputWithFullList).isEmpty());
}
}

Categories

Resources