Error in unit test case with MockRestServiceServer - java

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.

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 update dynamic date on body for post params within JVM PACT contract?

I have a POST request that takes date as a param from within my contract file for a PACT test.
return builder
.uponReceiving("A request to create a Zoom meeting")
.path(createMeeting)
.method("POST")
.headers(headers)
.body("{\"title\":\"My title\",\"start_time\":\"2020-08-28T14:30:00Z+01:00\",\"duration\":30,\"provider\":\"ZOOM\"}")
.willRespondWith()
.body(body)
.toPact();
But I'd like this to be dynamic, having perhaps today's or tomorrow's date, otherwise it would have an expired date. Could you please advise on how to do do this and if possible to keep it from the consumer side.
These are both Consumer and Provider samples for my request.
Consumer
#ExtendWith(PactConsumerTestExt.class)
public class PACTConsumerEdUiVcTest {
Map<String, String> headers = new HashMap<>();
String createMeeting = "/manage/create-meeting";
#Pact(provider = VC, consumer = ED_UI)
public RequestResponsePact createPact(PactDslWithProvider builder) {
headers.put("Content-Type", "application/json");
DslPart body = new PactDslJsonBody()
.date("start_time", "yyyy-MM-dd'T'HH:mm:ss.000'Z'", new Date());
return builder
.uponReceiving("A request to create a Zoom meeting")
.path(createMeeting)
.method("POST")
.headers(headers)
.body("{\"title\":\"My title\",\"start_time\":\"2020-08-28T14:30:00Z+01:00\",\"duration\":30,\"provider\":\"ZOOM\"}")
.willRespondWith()
.body(body)
.toPact();
}
#Test
#PactTestFor(providerName = VC, port = "8080")
public void runTest() {
//Mock url
RestAssured.baseURI = "http://localhost:8080";
Response response = RestAssured //todo: dynamic start time that won't expire. 27/08/2020
.given()
.headers(headers)
.when()
.body("{\"title\":\"My title\",\"start_time\":\"2020-08-28T14:30:00Z+01:00\",\"duration\":30,\"provider\":\"ZOOM\"}")
.post(createMeeting);
assert (response.getStatusCode() == 200);
}
}
Provider
#Provider(VC)
#PactFolder("target/pacts")
public class PactProviderEdUiVcTest {
#TestTemplate
#ExtendWith(PactVerificationInvocationContextProvider.class)
void pactTestTemplate(PactVerificationContext context, HttpRequest request) {
request.addHeader("Authorization", AUTHORIZATION_TOKEN);
context.verifyInteraction();
}
#BeforeEach
void before(PactVerificationContext context) {
context.setTarget(new HttpsTestTarget(BASE_PACT_VC_URL, 443, "/"));
getAuthorizationToken(UserType.TEACHER);
}
#State("A request to create a Zoom meeting")
public void sampleState() {
}
}
Many thanks.
Able to make it working changing the RestAssured implementation to accept a map and use the date as its value.
map.put("start_time", new Date().toString());
Here the full piece.
#Test
#PactTestFor(providerName = VC, port = "8080")
public void runTest() {
//Mock url
RestAssured.baseURI = "http://localhost:8080";
Map<String, Object> map = new HashMap<>();
map.put("title", "MyTitle");
map.put("start_time", new Date().toString());
map.put("duration", 30);
map.put("provider", "ZOOM");
Response response = RestAssured //todo: dynamic start time that won't expire. 27/08/2020
.given()
.headers(headers)
.when()
.body(map)
.post(createMeeting);
assert (response.getStatusCode() == 200);
}

How To test spring Resource file using junit and mockito

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.

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 do GET API Request with URL params?

Client client = ClientBuilder.newClient();
urlApi="https://localhost:123/demo/api/v1/rows/search?";
WebTarget webTarget = client.target(urlApi);
for (Map.Entry<String, String> entry : queryParams.entrySet()) {
webTarget.queryParam(entry.getKey(), entry.getValue());
}
webTarget.queryParam("searchConditions",webTarget.queryParam("mobileNo","+9999999999"));
Invocation.Builder builder = webTarget.request();
builder.header("id", "ABC");
String asB64 = Base64.getEncoder().encodeToString("ABC:PWD".getBytes("utf-8"));
logger.debug("Calling API "+urlApi);
builder.header("Authorization", "Basic "+asB64);
builder.header("Content-type", MediaType.APPLICATION_JSON);
response = builder.get();
responseData = response.readEntity(String.class);
System.out.println(responseData);
I am trying to do GET request with searchCondition as Key and value as {mobileNo="+919999999999"}, I am unable to get this to work.
Apart from that, how can I print the Request "Headers" along with "Query params"? Thank you in advance
I think you need to encode the value inputs, something like this:
webTarget.queryParam("searchCondition", URLEncoder.encode("{mobileNo=\"+919999999999\"}", StandardCharsets.UTF_8.toString()));
UDPATE:
Example of the rest client with Spring:
#Test
public void testStack() throws Exception {
RestTemplate rest = new RestTemplate();
String fooResourceUrl="http://localhost:8080/usersParam?";
RestTemplate restTemplate = new RestTemplate();
String parameter = "{mobileNo=\"+919999999999\"}";
ResponseEntity<String> response = restTemplate.getForEntity(fooResourceUrl + "parameter=" + URLEncoder.encode(parameter, StandardCharsets.UTF_8.toString() ), String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
}
And this would be the rest service:
#RequestMapping(method = RequestMethod.GET, value="/usersParam")
public User getUsersInfo(#RequestParam String parameter) throws UnsupportedEncodingException {
System.out.println(URLDecoder.decode(parameter, StandardCharsets.UTF_8.toString() ));
return null;
}

Categories