i want to mock the request entity and response to test the method on the controller method, this code has been written by another developer and i am supposed to test it using mockito.i'm mocking the controller class
i am trying to mock the request entity value and the respionse entity value , but it's not working and i'm getting a reflection error when i'm trying to debug
public class InquiryController {
private static final Logger log =
LoggerFactory.getLogger(InquiryController.class);
#Autowired
private InquiryProperties inquiryProperties;
#Autowired
private InquiryService inquiryService;
#Autowired
RestTemplate restTemplate;
public static int count = 0;
#Bean
private RestTemplate getRestTemplate() {
return new RestTemplate();
}
#PostMapping(value = "/endCustomer", produces = { MediaType.APPLICATION_JSON_VALUE }, consumes = {
MediaType.APPLICATION_JSON_VALUE })
public ResponseEntity<List<EndCustomerDTO>> endCustomer(#RequestBody CustomerInfo customerInfo)
throws IOException, JSONException {
log.info("### InquiryController.endCustomer() ===>");
List<EndCustomerDTO> endCustomerDTOs = null;
try {
//RestTemplate restTemplate = new RestTemplate();
RequestEntity<CustomerInfo> body = RequestEntity.post(new URI(inquiryProperties.getEndCustomer()))
.accept(MediaType.APPLICATION_JSON).body(customerInfo);
ResponseEntity<List<EndCustomerDTO>> response = restTemplate.exchange(body,
new ParameterizedTypeReference<List<EndCustomerDTO>>() {
});
endCustomerDTOs = (response != null ? response.getBody() : new ArrayList<EndCustomerDTO>());
} catch (RestClientException | URISyntaxException e) {
log.error("InquiryController.endCustomer()" + e.getMessage());
}
log.info("### END InquiryController.endCustomer() ===>");
if (null == endCustomerDTOs) {
return new ResponseEntity<List<EndCustomerDTO>>(new ArrayList<EndCustomerDTO>(), HttpStatus.OK);
}
return new ResponseEntity<List<EndCustomerDTO>>(endCustomerDTOs, HttpStatus.OK);
}
It's because instance of RestTemplate is not injected through Spring IOC when you do the REST call. You need to declare the getRestTemplate method of in the component class which is scanned during application startup or in other words during component scan. Thus making restTemplate available for autowire.
Once you separate the config from the controller as #chrylis suggested, you proceed further like this.
You must be trying to mock the RequestEntity.post method. Note that it is a static method and is mocked a bit differently than the usual public instance methods. For this, you need to use PowerMockito as Mockito won't do.
add the dependency in pom like this:
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito</artifactId>
<version>1.6.5</version>
<scope>test</scope>
</dependency>
then anotate the test class with #RunWith, and #PrepareForTest like so:
#RunWith(PowerMockRunner.class)
#PrepareForTest({RequestEntity.class})
public class TestClass {
}
and the mock the post method as so:
PowerMockito.mockStatic(RequestEntity.class); when(RequestEntity.post(any(URI.class))).thenReturn(getRequestEntityResponseBody());
private RequestEntity< CustomerInfo > getRequestEntityResponseBody(){
//code
}
UPDATE
CustomerInfo customerInfo = new CustomerInfo();
HttpHeaders responseHeaders = new HttpHeaders();
responseHeaders.set("MyResponseHeader", "MyValue");
RequestEntity<CustomerInfo> customerInfoRequestEntity = new ResponseEntity<CustomerInfo>(customerInfo, responseHeaders, HttpStatus.OK);
PowerMockito.mockStatic(RequestEntity.class);
when(RequestEntity.post(any(URI.class))).thenReturn(customerInfoRequestEntity);
Related
Can someone please, tell me how you can write a test. I now have to test sending a request from one server to another using RestTemplate.
class ServiceTest {
#Mock
private RestTemplate restTemplate = new RestTemplate();
#InjectMocks
private RConsumerService refundConsumerService = new RConsumerService(new RestTemplateBuilder());
#Test
public void sendRequestToBillingService(){
ChargeResponse chargeResponse = new ChargeResponse();
chargeResponse.setInstanceKey("testInstanceKey");
KafkaMessage kafkaMessage = new KafkaMessage();
kafkaMessage.setApplication_id(1L);
kafkaMessage.setCompany_id(1111);
TransactionRequestContext reqContext = refundConsumerService.createTxnRequestContext(kafkaMessage);
Mockito.when(restTemplate.postForEntity(Mockito.any()
, refundConsumerService.buildChargeRequest(reqContext), ChargeResponse.class))
.thenReturn(new ResponseEntity<>(chargeResponse, HttpStatus.OK));
refundConsumerService.refund(kafkaMessage);
assertEquals(chargeResponse.getInstanceKey(), "testInstanceKey");
}
}
How do I write the condition correctly in
Mockito.when(restTemplate.postForEntity(Mockito.any()
, refundConsumerService.buildChargeRequest(reqContext), ChargeResponse.class))
.thenReturn(new ResponseEntity<>(chargeResponse, HttpStatus.OK));
Now I am getting this exception java.lang.IllegalArgumentException: URI is required
As you are using #Mock and #InjectMocks, you don't need to create new instance of those objects. Mockito will inject it for you. I guess you have this exception because of this parameter : Mockito.any() in your Mockito.when(). It have to be of a Uri type.
Your code will looks like this :
#ExtendWith(MockitoExtension.class)
class ServiceTest {
#Mock
private RestTemplate restTemplate;
#InjectMocks
private RConsumerService refundConsumerService;
#Test
public void sendRequestToBillingService() {
ChargeResponse chargeResponse = new ChargeResponse();
chargeResponse.setInstanceKey("testInstanceKey");
KafkaMessage kafkaMessage = new KafkaMessage();
kafkaMessage.setApplication_id(1L);
kafkaMessage.setCompany_id(1111);
TransactionRequestContext reqContext = refundConsumerService.createTxnRequestContext(kafkaMessage);
URI mockUri = URI.create("http://localhost/mockUri");
Mockito.when(restTemplate.postForEntity(mockUri
, refundConsumerService.buildChargeRequest(reqContext), ChargeResponse.class))
.thenReturn(new ResponseEntity<>(chargeResponse, HttpStatus.OK));
refundConsumerService.refund(kafkaMessage);
assertEquals(chargeResponse.getInstanceKey(), "testInstanceKey");
}
}
When I create a case where exception is thrown by the code by calling APIs, at that time, ExceptionHandler is invoked as expected. But when I try creating the same case through unit tests, at that time, ExceptionHandler is not invoked. My classes are as below:
Controller.java
#Post("/XXX")
public ResponseEntity<List<CategoryTopicBean>> listCategoryTopics(#Body CategoryIdsRequestBean categoryIdsRequestBean) {
if (categoryIdsRequestBean.getCategoryIds().size() > MAX_ALLOWED_CATEGORY_SELECTION) {
throw new CustomException(SystemConstants.ResponseCode.ERROR, SystemConstants.ResponseMessage.OVERFLOW_MAX_CATEGORIES);
}
...
CustomExceptionHandler.java:
#Produces
#Singleton
#Requires(classes = {CustomException.class, ExceptionHandler.class})
public class CustomExceptionHandler implements ExceptionHandler<CustomException, HttpResponse> {
#Override
public HttpResponse handle(HttpRequest request, CustomException exception) {
return HttpResponse.ok(new ResponseEntity<>(exception.responseCode, exception.getMessage()));
}
}
XXXShould.java
#Test
public void should_list_category_topics() {
CategoryIdsRequestBean categoryIdsBean = new CategoryIdsRequestBean();
IdBean idBean = new IdBean();
idBean.setId(ID_1);
categoryIdsBean.setCategoryIds(Arrays.asList(idBean));
ResponseEntity<List<CategoryTopicBean>> responseEntity = topicController.listCategoryTopics(categoryIdsBean);
assertThat(SystemConstants.ResponseCode.SUCCESS).isEqualTo(responseEntity.getResponseCode());
assertThat(1).isEqualTo(responseEntity.getData().size());
categoryIdsBean = new CategoryIdsRequestBean();
categoryIdsBean.setCategoryIds(Arrays.asList(idBean, idBean, idBean, idBean, idBean, idBean));
responseEntity = topicController.listCategoryTopics(categoryIdsBean);
}
Can anyone please look into this, and help me out?
The problem here is, you are testing the controller by directly invoking the controller method
topicController.listCategoryTopics(categoryIdsBean).
This is not a good approach to test controller functionality. What you should do is use MicronautTest. MicronautTest will start an embedded server. Now you can use an HTTP client to hit the endpoint and retrieve the result.
Your code needs to be changed to something around the lines as below.
#MicronautTest
class HelloWorldTest {
#Inject
#Client("/")
RxHttpClient client;
#Test
public void should_list_category_topics() {
// Test Data
CategoryIdsRequestBean categoryIdsBean = new CategoryIdsRequestBean();
IdBean idBean = new IdBean();
idBean.setId(ID_1);
categoryIdsBean.setCategoryIds(Arrays.asList(idBean));
HttpRequest<String> request = HttpRequest.POST("/XXX", categoryIdsBean);
ResponseEntity<List<CategoryTopicBean>> retrieve = client.toBlocking().retrieve(request, ResponseEntity.class);
categoryIdsBean = new CategoryIdsRequestBean();
categoryIdsBean.setCategoryIds(Arrays.asList(idBean, idBean, idBean, idBean, idBean, idBean));
responseEntity = topicController.listCategoryTopics(categoryIdsBean);
}
}
For the exception case scenario, as the exception handler returns ResponseEntity<String>, you would need to make a minor change in the above code.
ResponseEntity<String> retrieve = client.toBlocking()
.retrieve(request, ResponseEntity.class);
If your controller calls any other service, do not forget to mock the behavior.
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.
I am using swagger 3.0.0-Snapshot to create documentation for my Spring Boot application.
My maven dependencies are
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>3.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>3.0.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-spring-webmvc</artifactId>
<version>3.0.0-SNAPSHOT</version>
</dependency>
My swagger config class is as simple as possible:
#Configuration
#EnableSwagger2WebMvc
public class SwaggerConfig {
#Bean
public Docket api() {
return new Docket(DocumentationType.SWAGGER_2)
.useDefaultResponseMessages(false)
.select()
.apis(RequestHandlerSelectors.basePackage("com.mycompany.cs"))
.paths(PathSelectors.any())
.build()
.pathMapping("/")
.useDefaultResponseMessages(false);
}
And my controller method has the following annotation:
#ApiOperation(value = "Hello world", httpMethod = "POST")
#ApiResponses(value = {
#ApiResponse(code = 200, message = "OK",
examples = #Example(value = #ExampleProperty(mediaType = "application/json",
value = exampleValue)))
})
It is working and shows in Swagger UI "Example Value" field value that has constant string exampleValue that is private static String.
The question is how to pass the content of json file that is in resources folder to #ExampleProperty value?
I tried to read file content in static block and pass it to initialize final String with it, but then the compiler says that "Attribute value has to be constant".
The content of json file must be shown in example field in Swagger UI.
Good news is that Swagger is using Spring and it is possible to use the power of DI.
For instance, you want to add new functionality to ServiceModelToSwagger2MapperImpl. Create your own component that extends it and mark it primary. Spring will autowire your implementation of ServiceModelToSwagger2Mapper abstract class.
#Component
#Primary
#Slf4j
public class ServiceModelToSwagger2MapperExtensionImpl extends ServiceModelToSwagger2MapperImpl {
For instance, you want it to read the content of the file and put it to the example field:
#Override
protected Map<String, Response> mapResponseMessages(Set<ResponseMessage> from) {
Map<String, Response> responses = super.mapResponseMessages(from);
responses.forEach((key, response)-> {
Map<String, Object> examples = response.getExamples();
examples.entrySet().forEach(example -> {
Object exampleObject = example.getValue();
if (exampleObject instanceof String) {
String exampleValue = (String) exampleObject;
if (exampleValue.startsWith("file:")) {
String fileContent = readFileContent(exampleValue);
example.setValue(fileContent);
}
}});
});
return responses;
}
private String readFileContent(String example) {
String fileContent = "";
try {
String fileName = example.replace("file:", "");
File resource = new ClassPathResource(fileName).getFile();
if(resource.exists()) {
fileContent
= new String(Files.readAllBytes(resource.toPath()));
}
} catch (
IOException e) {
log.error("Cannot read swagger documentation from file {}", example);
}
return fileContent;
}
And here is an example of usage in your controller:
#ApiResponses(value = {
#ApiResponse(code = 200, message = "OK",
examples = #Example(value = #ExampleProperty(mediaType = "application/vnd.siren+json",
value = "file:/data/controller-responses/reponse.json")))
})
I use external API, which returns list of sorted by date Objects with many (approx. 30) properties.
I wrote simple Rest API using Spring Boot with one endpoint
/newest_obj_name
which just return currently newest name of Object from that list and ignore everything else.
How can I sufficiently test that code while the value from external API is constantly changing, so I cannot simply use String expected as in a code below?
Generally speaking how to approach whole testing issue in that scenario?
#RunWith(SpringRunner.class)
#SpringBootTest(classes = Application.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyTest {
#LocalServerPort
private int port;
private TestRestTemplate restTemplate = new TestRestTemplate();
private HttpHeaders headers = new HttpHeaders();
#Test
public void testRetrieveNewest() {
HttpEntity<String> entity = new HttpEntity<String>(null, headers);
ResponseEntity<String> response = restTemplate.exchange(
createURLWithPort("/newest_obj_name"),
HttpMethod.GET, entity, String.class);
String expected = "{\"name\":\"crazy\"}";
try {
JSONAssert.assertEquals(expected, response.getBody(), false);
} catch (JSONException e) {
e.printStackTrace();
}
}
private String createURLWithPort(String uri) {
return "http://localhost:" + port + uri;
}
}