How To test spring Resource file using junit and mockito - java

im working in a spring boot projet where i create an api that return a file from classpath and all works fine , this is my api :
#Value(value = "classpath:pdf/notice_file.pdf")
private Resource myPdfResource;
#GetMapping("/getLocalDocument/{typeDoc}")
public ResponseEntity<byte[]> getLocalDocument(#PathVariable String typeDoc)
{
byte[] contents = new byte[0];
HttpStatus status = HttpStatus.OK;
HttpHeaders headers = new HttpHeaders();
final InputStream in;
String filename="";
try {
headers.setContentType(MediaType.APPLICATION_PDF);
if ("NOTICE".eqauls(typeDoc)) {
in = myPdfResource.getInputStream();
contents = IOUtils.toByteArray(in);
filename = "notice_1.pdf";
}
headers.setContentDispositionFormData(filename, filename);
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
return new ResponseEntity<>(contents, headers, status);
} catch (Exception e) {
LOG.error(e.getMessage(), e);
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
all the tests methods are ok but i'm getting an error with the method getLocalDocumentTest , and this is my unit test code :
#RunWith(SpringRunner.class)
#PrepareForTest(IOUtils.class)
public class ApiTest{
#Mock
private Resource myPdfResource;
#InjectMocks
private Api api;
private MockMvc mockMvc;
#Before
public void setUp() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(api).build();
}
#Test
public void getLocalDocumentTest() throws Exception {
String typeDoc= "NOTICE";
byte[] contents = new byte[0];
InputStream stubInputStream = IOUtils.toInputStream("some test data for my input stream", "UTF-8");;
String URI = "/v1/getLocalDocument/"+typeDoc;
when(myPdfResource.getInputStream()).thenReturn(stubInputStream);
PowerMockito.mockStatic(IOUtils.class);
PowerMockito.when(IOUtils.toByteArray(any(InputStream.class))).thenReturn(contents);
RequestBuilder requestBuilder = MockMvcRequestBuilders.get(URI);
MvcResult mvcResult = mockMvc.perform(requestBuilder).andReturn();
MockHttpServletResponse response = mvcResult.getResponse();
assertEquals(HttpStatus.OK.value(), response.getStatus());
}
}
when i run the test i'm getting the following error :
You cannot use argument matchers outside of verification or stubbing.
Examples of correct usage of argument matchers:
when(mock.get(anyInt())).thenReturn(null);
doThrow(new RuntimeException()).when(mock).someVoidMethod(anyObject());
verify(mock).someMethod(contains("foo"))
Also, this error might show up because you use argument matchers with methods that cannot be mocked.
Following methods *cannot* be stubbed/verified: final/private/equals()/hashCode().
do you have any idea please why i'm getting this error , im new in mockito framework
Thanks.

Related

How to test a spring postmapping? (Junit)

Im trying to test a sample post where you have a endpoint called /message which is a path parameter on localhost. The message is a var so if I post /samplemsg as an example it should print that. However Im not quite sure how to test the post. Here's what I've managed to do so far
#RestController
#Component
#RequestMapping(path = "/message")
public class HomeController {
#PostMapping(path="/message")
public ResponseEntity<Object> postName(#PathParam ("message") #RequestBody String message) {
URI location = URI.create(ServletUriComponentsBuilder.fromCurrentRequest().buildAndExpand(message + " was created").toUriString());
return ResponseEntity.created(location).build();
}
Test Class
#RunWith(SpringRunner.class)
#SpringBootTest(classes= RunApplication.class, webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
class RunApplicationTests {
#Autowired
private TestRestTemplate restTemplate;
#Test
void sendPost() throws URISyntaxException {
final String baseUrl = "http://localhost:8080/message";
URI uri = new URI(baseUrl);
String message = "sample msg";
HttpHeaders headers = new HttpHeaders();
headers.set("X-COM-PERSIST", "true");
HttpEntity<String> request = new HttpEntity<>(message, headers);
ResponseEntity<String> result = this.restTemplate.postForEntity(uri, request, String.class);
Assert.assertEquals("sample msg was created", result.getBody().toString());
}
}
Error Message:
org.junit.ComparisonFailure: expected:<[sample msg was created]> but was:<[{"timestamp":"2022-02-14T21:54:29.152+00:00","status":404,"error":"Not Found","path":"/message/"}]>
Expected :sample msg was created
Actual :{"timestamp":"2022-02-14T21:54:29.152+00:00","status":404,"error":"Not Found","path":"/message/"}

How to test restclient using RestTemplate and JUnit?

I am new to JUNIT and using RestTemplate to call my service, I'm getting 200 response for the same. But, I can't test the class using JUnit. Tried different approaches and getting 400 and 404. I want to post the request body (json) and test the status. Please let me know if there is any issue.
/**
* Rest client implementation
**/
public class CreateEmailDelegate implements CDM {
#Autowired
private RestTemplate restTemplate;
private String url = "http://example.com/communications/emails";
public ResponseEntity<CDResponse> createEmail(CDMEmailRequest cDRequest) throws UnavailableServiceException, InvalidInputException {
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.set("SR_API_Key", SR_API_KEY);
httpHeaders.set("consumerIdentification", CONSUMER_IDENTIFICATION);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
HttpEntity< CDMEmailRequest > cDRequestEntity = new HttpEntity<>( cDRequest, httpHeaders);
ResponseEntity< CDResponse > cDResponse = null;
try {
cDResponse = restTemplate.postForEntity(url, cDRequestEntity, CDResponse.class);
} catch (Exception e) {
LOGGER.error(e.getMessage());
throw e;
}
return cDResponse;
}
}
My Test class which return 404 status instead of 200
#RunWith(SpringJUnit4ClassRunner.class)
public class CreateEmailCommunicationDelegateTest {
#Before
public void setup() {
httpHeaders = new HttpHeaders();
httpHeaders.set("SR_API_Key", SR_API_KEY);
httpHeaders.set("consumerIdentification", CONSUMER_IDENTIFICATION);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
DefaultMockMvcBuilder builder = MockMvcBuilders.webAppContextSetup(this.wac);
this.mockMvc = builder.build();
}
public void testResponse() throws Exception, HttpClientErrorException, JsonProcessingException {
String url = "http://example.com/CommunicationDeliveryManagement-Service-1.0.0/communications/emails";
CDMEmailRequest anObject = new CDMEmailRequest();
ResultMatcher ok = MockMvcResultMatchers.status().isOk();
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
ObjectWriter ow = mapper.writer().withDefaultPrettyPrinter();
String requestJson = ow.writeValueAsString(anObject);
System.out.println(requestJson);
MockHttpServletRequestBuilder builder = MockMvcRequestBuilders.post(url).contentType(MediaType.APPLICATION_JSON_UTF8).content(requestJson);
this.mockMvc.perform(builder).andExpect(ok).andDo(MockMvcResultHandlers.print());
}
}
My Test class using TestRestTemplate instead MockMvc returns 400
#RunWith(SpringJUnit4ClassRunner.class)
public class CreateEmailCommunicationDelegateTest {
#Before
public void setup() {
httpHeaders = new HttpHeaders();
// rest headers as above
}
#Test
public void testResponse() throws Exception, HttpClientErrorException, JsonProcessingException {
String url = "http://example.com/CommunicationDeliveryManagement-Service-1.0.0/communications/emails";
String username = "";
String password = "";
HttpEntity<CDMEmailRequest>
cDEntity = new HttpEntity<>(httpHeaders);
restTemplate = new TestRestTemplate(username, password);
responseEntity =
restTemplate.exchange(url, HttpMethod.POST, cDEntity,
CDResponse.class);
assertNotNull(responseEntity);
assertEquals(HttpStatus.OK,
responseEntity.getStatusCode());
}
}
I think you're trying to implement an integration test instead of an unit test, there is quite difference. MockMvc should be used to implement unit tests and TestRestTemplate for integration tests. You can't neither use it for testing a Client implementation.
See Unit and Integration Tests in Spring Boot
If you are working with Spring Boot you could achieve your goal using another approach see this question Spring boot testing of a rest client using #RestClientTest.

How to test injected mock with try-catch

I'm doing simple unit test by using mockMvc with springboot. SampleCtrl.java is origin source code and SampleCtrlTest.java is test source code. There are 3 mocks injected to SampleCtrl and they are working well except SampleService class. As you can see, SampleService wrapped with try-catch block. So, I have no idea how to call the method in mock class to get return or throw exception in test source code.
I removed try-catch block in origin code, also given() method in test code. It worked well. That's why I think the try-catch block is undoubted reason to make error.
SampleCtrl.java
#PostMapping(path = "/save", consumes = "application/json")
#ResponseBody
public ResponseEntity<Map<String, Object>> setEmp(#RequestBody
List<EmpSaveVo> vos) {
result.clear();
try {
msg = service.setEmp(vos);
} catch (Exception e) {
msg = e.getMessage();
}
result = messageTrans.getMapLang(msg);
return messageReturn.getRestResp(result, msg);
}
SampleCtrlTest.java
private MockMvc mockMvc;
#Mock
private SampleService service;
#Mock
private MessageTrans messageTrans;
#Mock
private MessageReturn messageReturn;
#InjectMocks
private SampleCtrl sampleCtrl;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
mockMvc = MockMvcBuilders.standaloneSetup(sampleCtrl).build();
}
#Test
public void givenEmployeeDataWhenPostEmpSave() throws Exception {
List<EmpSaveVo> empSaveVos = new ArrayList<>();
EmpSaveVo empSaveVo = new EmpSaveVo();
empSaveVo.setEmployeeId(100L);
empSaveVo.set_status((long) Status.Modified.getStatus());
empSaveVos.add(empSaveVo);
Gson gson = new Gson();
String element = gson.toJson(empSaveVos);
String msg = "Test";
Map<String, Object> result = new HashMap<>();
result.put("message", msg);
given(service.setEmp(empSaveVos)).willThrow(new Exception());
given(messageTrans.getMapLang(msg)).willReturn(result);
given(messageReturn.getRestResp(any(), anyString()))
.willReturn(new ResponseEntity<Map<String, Object>>(result, HttpStatus.OK));
mockMvc.perform(post("/api/emp/save")
.content(element)
.contentType(MediaType.APPLICATION_JSON)).andDo(print())
.andExpect(status().isOk());
}
Consequently, I want to see this console log.
MockHttpServletResponse:
Status = 200
Error message = null
Headers = [Content-Type:"application/json;charset=UTF-8"]
Content type = application/json;charset=UTF-8
Body = {"message":"Test"}
Forwarded URL = null
Redirected URL = null
Cookies = []

How test this service using spring

I am trying to test the restTemplate.exchange but my test always skips the Try
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<String>("parameters", headers);
String uri = resultado.getDatos().getPeticion().getUrl();
ResponseEntity<ResultadoPeticionDto> respuesta = null;
try{
respuesta = restTemplate.exchange(uri, HttpMethod.GET, entity, ResultadoPeticionDto.class);
resultado.getDatos().setFechaFin(new Date());
Calificacion calificacion = null;
resultado.getDatos().setResultado(calificacion.valueOf(respuesta.getBody().getCodigoError()));
resultado.getDatos().setMensaje(respuesta.getBody().getMensaje());
}catch (ResourceAccessException e) {
resultado.setCodigo(404);
resultado.setSuccess(false);
return resultado;
}catch (Exception e) {
resultado.setCodigo(500);
resultado.setSuccess(false);
return resultado;
}
this is my Mockito in the test:
Mockito.when(restTemplate.exchange(Mockito.anyString(),
Mockito.eq(HttpMethod.GET), Mockito.<HttpEntity<?>> any(),
Mockito.eq(ResultadoPeticionDto.class))).thenReturn(response);
peticionManager.peticion(resultado);
but it doesn't work, in the line of the request it run normally and skip my configuraction in the when, i'm using
#Mock
private RestTemplate restTemplate;
#InjectMocks
PeticionManager peticionManager;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
in the test class, any idea?
The katch captures the exception (code 500) and fails to provide coverage when attempting to be the target of my test

Error in unit test case with MockRestServiceServer

I am using MockRestServiceServer for unit testing my rest end point. I have one unit test in working condition when I use
mockServer.expect(requestTo(containsString(ROOT_RESOURCE_PATH))).andExpect(method(HttpMethod.POST))
.andRespond(withSuccess(response, MediaType.TEXT_PLAIN));
But same fails when I use
mockServer.expect(requestTo(containsString(ROOT_RESOURCE_PATH))).andExpect(method(HttpMethod.POST))
.andRespond(withBadRequest().body("test").contentType( MediaType.TEXT_PLAIN));
Here is complete code
#Test
public void testPost() {
ClientHttpRequestFactory originalRequestFactory = restTemplate.getRequestFactory();
mockServer = MockRestServiceServer.createServer(restTemplate);
try {
WebTarget target = getRootTarget("/test").path("");
String payLoad = ReadFile("src/test/resources/SamplePayload.html");
String response = ReadFile("src/test/resources/SampleResponse.txt");
Assert.assertNotNull(payLoad);
Assert.assertNotNull(response);
final javax.ws.rs.client.Entity<String> entity = javax.ws.rs.client.Entity.entity(payLoad, "text/plain");
mockServer.expect(requestTo(containsString(ROOT_RESOURCE_PATH))).andExpect(method(HttpMethod.POST))
.andRespond(withSuccess(response, MediaType.TEXT_PLAIN));
final Response mockResponse = target.request().post(entity);
mockServer.verify();
Assert.assertNotNull("Response must not be null", mockResponse.getEntity());
Assert.assertEquals("Response does not have expected response code", 200, mockResponse.getStatus());
} finally {
restTemplate.setRequestFactory(originalRequestFactory);
}
}
#Test
public void testPostWithEmptyBody() {
ClientHttpRequestFactory originalRequestFactory = restTemplate.getRequestFactory();
mockServer = MockRestServiceServer.createServer(restTemplate);
try{
WebTarget target = getRootTarget("/test").path("");
String entityBody = new String();
final javax.ws.rs.client.Entity<String> entity = javax.ws.rs.client.Entity.entity(entityBody, "text/plain");
mockServer.expect(requestTo(containsString(ROOT_RESOURCE_PATH))).andExpect(method(HttpMethod.POST))
.andRespond(withBadRequest().body("test").contentType( MediaType.TEXT_PLAIN));
final Response response = target.request().post(entity);
mockServer.verify();
Assert.assertNotNull("Response must not be null", response.getEntity());
Assert.assertEquals("Response does not have expected response code", 400, response.getStatus());
}finally {
restTemplate.setRequestFactory(originalRequestFactory);
}
}
target.request().post() is funciton which just calls
resttemplate.postForEntity
In second test case I am expecting a status code of 400 but instead I am getting 500 .Any suggestions?
Maybe your RestTemplate not contains right MessageConvertor for resolving
MediaType.TEXT_PLAIN.

Categories