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/"}
Related
I have a spring boot application that makes an API hit of other internal projects using the rest template which works fine and I am writing unit test cases for it but test case if failing due to Unexpected exception thrown: java.lang.NullPointerException: Cannot invoke "org.springframework.http.ResponseEntity.getBody()" because "response" is null
Service
#Service
#Slf4j
public class DynamoDBServiceImpl implements DynamoDBService {
private final RestTemplate restTemplate;
private final HttpHeaders httpHeaders;
private final String jwtHeader;
private final String apiKeyHeader;
private final String dynamodbSysApiKey;
private final String fetchAdminGroupUrl;
public DynamoDBServiceImpl(
RestTemplate restTemplate,
HttpHeaders httpHeaders,
#Value("${header-name.jwt}") String jwtHeader,
#Value("${header-name.api-key}") String apiKeyHeader,
#Value("${dynamodb-sys-api-key}") String dynamodbSysApiKey,
#Value("${dynamodb-fetch-admin-group-url}") String fetchAdminGroupUrl) {
this.restTemplate = restTemplate;
this.httpHeaders = httpHeaders;
this.jwtHeader = jwtHeader;
this.apiKeyHeader = apiKeyHeader;
this.dynamodbSysApiKey = dynamodbSysApiKey;
this.fetchAdminGroupUrl = fetchAdminGroupUrl;
}
#Override
public List<AdminGroupDTO> getAllAdminGroups() {
log.debug("Request to get admin group details with url : {}", fetchAdminGroupUrl);
httpHeaders.set("Accept", MediaType.APPLICATION_JSON_VALUE);
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
httpHeaders.setBearerAuth(CommonUtils.getHeaderFromCurrentHttpRequest(jwtHeader));
httpHeaders.set(apiKeyHeader, dynamodbSysApiKey);
HttpEntity<AdminGroupDTO> request = new HttpEntity<>(httpHeaders);
ResponseEntity<List<AdminGroupDTO>> response =
restTemplate.exchange(fetchAdminGroupUrl, HttpMethod.GET, request, new ParameterizedTypeReference<List<AdminGroupDTO>>() {});
return response.getBody();
}
}
Test
#SpringBootTest(classes = Application.class)
public class DynamoDBServiceTest {
private final RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
private final HttpHeaders httpHeaders = new HttpHeaders();
private final DynamoDBServiceImpl dynamoDBService =
new DynamoDBServiceImpl(
restTemplate, httpHeaders, "Authorization" , "Api-Key", "fake", "https://fake.com");
#Test
void testGetAllAdminGroups() {
List<AdminGroupDTO> adminGroupDTOList = new ArrayList<>();
AdminGroupDTO adminGroupDTO = new AdminGroupDTO();
adminGroupDTO.setAdminGroupId(1L);
adminGroupDTO.setAdminGroupName("fake");
adminGroupDTO.setCountryName("fake");
adminGroupDTOList.add(adminGroupDTO);
ResponseEntity<List<AdminGroupDTO>> responseEntity = new ResponseEntity<>(adminGroupDTOList, HttpStatus.OK);
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<List<AdminGroupDTO>>>any()))
.thenReturn(responseEntity);
assertDoesNotThrow(dynamoDBService::getAllAdminGroups);
}
}
Replace this line of code :
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.<Class<List<AdminGroupDTO>>>any()))
.thenReturn(responseEntity);
With this :
when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(),
ArgumentMatchers.eq(new ParameterizedTypeReference<List<AdminGroupDTO>>() {}))
)
.thenReturn(responseEntity);
And excepption should dissapear.
For futher details you can check this post.
I have a method that sends a rest request to an api with multipart-formdata, this will upload a file to the external api. However, I am not able to finish the unit test method for this.
The first problem I am finding is that the content-type that I am expecting is always different than the one that method create. For some reason when sending the request the mediatype is multipart-formdata but the header is set as that in addition to charset and boundary. The latter, boundary, is always changing its value therefore I can not set the expected value on the unit tests because it will always be different.
Apart from that, how do I also expect that the content of the request is the same content that I initiated the test with? How do I assert that the payload is the same.
Please check the code:
Service class:
#Service
#Slf4j
public class JiraService {
private HttpHeaders createRequestHeaders(JiraClient jiraClient, MediaType contenType) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(contenType);
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
headers.setBasicAuth(jiraClient.getUsername(), jiraClient.getPassword());
return headers;
}
private <EC, RC> ResponseEntity<RC> createRequestAndSend(HttpMethod method, String url, HttpHeaders headers,
EC payload, Class<RC> responseType) {
HttpEntity<EC> requestEntity = new HttpEntity<>(payload, headers);
ResponseEntity<RC> responseEntity = restTemplate.exchange(url, method, requestEntity, responseType);
// TODO deal with response
log.error("Loggin something");
return responseEntity;
}
public void addAttachment(JiraClient jiraClient, JiraIssue jiraIssue, JiraAttachment jiraAttachment)
throws MalformedURLException, IOException {
String url = jiraClient.getHost() + "/rest/api/2/issue/" + jiraIssue.getKey() + "/attachments";
HttpHeaders headers = createRequestHeaders(jiraClient, MediaType.MULTIPART_FORM_DATA); // What to do here?
headers.set("X-Atlassian-Token", "no-check");
FileSystemResource file = jiraAttachment.downloadFileFromWeb();
MultiValueMap<String, Object> payload = new LinkedMultiValueMap<>();
payload.add("file", file);
createRequestAndSend(HttpMethod.POST, url, headers, payload, String.class);
jiraAttachment.deleteFileFromSystem();
}
}
ServiceTest.class
#ActiveProfiles("test")
#RestClientTest(JiraService.class)
public class JiraServiceTest {
#Value("classpath:jira/add_attachment/validJiraAttachmentAddition.json")
private Resource validJiraAttachmentAddition;
#Autowired
private MockRestServiceServer server;
#Autowired
private JiraService jiraService;
#Mock
private JiraAttachment mockJiraAttachment;
private FileSystemResource attachmentFileSystemResource;
#BeforeEach
public void setupTests() throws IOException {
// initialize mocks
}
#Test
public void addAttachment_WithValidData_ShouldAddAttachmentToJiraIssue() throws Exception {
String url = host + "/rest/api/2/issue/" + issueKey + "/attachments";
ResponseActions stub = createServiceStub(HttpMethod.POST, url, MediaType.MULTIPART_FORM_DATA_VALUE);
stub = stub.andExpect(header("X-Atlassian-Token", "no-check"));
stub.andRespond(withSuccess());
// How to assert that the content of the request is the same as the resource?
when(mockJiraAttachment.downloadFileFromWeb()).thenReturn(attachmentFileSystemResource);
jiraService.addAttachment(mockJiraClient, mockJiraIssue, mockJiraAttachment);
}
private ResponseActions createServiceStub(HttpMethod method, String url, String contenType) {
String encodedCredentials = Base64.getEncoder().encodeToString((username + ":" + password).getBytes());
ResponseActions stub = server.expect(ExpectedCount.once(), requestTo(url));
stub = stub.andExpect(method(method));
stub = stub.andExpect(header("Content-Type", contenType)); // How to expect the content type here ?
stub = stub.andExpect(header("Authorization", "Basic " + encodedCredentials));
return stub;
}
}
Use ContentRequestMatchers.contentTypeCompatibleWith(MediaType contentType)
import static org.springframework.test.web.client.match.MockRestRequestMatchers.content;
...
stub.andExpect(content().contentTypeCompatibleWith(MediaType.MULTIPART_FORM_DATA))
i'm using Spring Boot for making Rest Controllers.
my controller is :
#RestController
public class VersionRestController {
#Autowired
VersionService versionService;
#GetMapping(value = "/csv", produces = "text/csv")
#ResponseStatus(value = HttpStatus.OK)
public void exportCsv(HttpServletResponse response) throws Exception {
String fileName = "allVersions.csv";
response.setHeader(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + fileName + "\"");
StatefulBeanToCsv<Version> writer = new StatefulBeanToCsvBuilder<Version>(response.getWriter())
.withQuotechar(CSVWriter.NO_QUOTE_CHARACTER).withSeparator(CSVWriter.DEFAULT_SEPARATOR)
.withOrderedResults(true).build();
writer.write(versionService.findAll());
}
}
im calling it like this
public void exportVersionAsCsv(){
final String uri = "http://localhost:8070/csv";
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<Version> response = restTemplate.getForEntity(uri, Version.class);
}
when i call the rest method direct in the browser it works fine, but when i call exportVersionAsCsv() in vaadin on click button it gives me org.springframework.web.client.HttpClientErrorException$NotAcceptable: 406 Not Acceptable
why is this happening ? any suggestion ?
thank you
Try this set setAccept to Media type to that is being produced by url you are consuming.
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
HttpEntity<String> entity = new HttpEntity<>("body", headers);
restTemplate.exchange(url, HttpMethod.POST, entity, String.class);
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 have a rest service written using Spring Boot as below:
#RestController
class MyBankingController{
#GetMapping("/getCards")
public SomePOJO getCards(){}
#GetMapping("/cardPresent")
public boolean isCardPresent(#RequestParam(value = "username") String
username){
//calls service layer to return primitive true or false
}
}
Below is my test class:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = MyBankingApplication.class, webEnvironment =
SpringBootTest.WebEnvironment.RANDOM_PORT)
public class MyBankingControllerIT {
private MyBankingController myBankingController;
private TestRestTemplate restTemplate;
private static final String BASE_URL = "/company/cards";
HttpHeaders headers = new HttpHeaders();
String username = "1234";
#Autowired
private MyBankingService myBankingService;
#LocalServerPort
private int port;
#Before
public void setUp() throws Exception {
myBankingController = new MyBankingController(myBankingService);
restTemplate = new TestRestTemplate();
}
#Test
public void testIsCardPresent() throws JSONException {
String url = BASE_URL+"cardPresent?username="+username;
HttpEntity<String> entity = new HttpEntity<String>(null, headers);
ResponseEntity<Boolean> response = restTemplate.exchange(
createURLWithPort(url),
HttpMethod.GET, entity, Boolean.class);
assertTrue(response.getBody());
}
private String createURLWithPort(String uri) {
return "http://localhost:" + port + uri;
}
}
I am unable to test this boolean return type. I have tried a couple of different things but it doesn't work. I am getting the below error.
org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of java.lang.Boolean out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of java.lang.Boolean out of START_OBJECT token at [Source: (PushbackInputStream); line: 1, column: 1]
Please note that the above code is just a customized version of the actual code and that at the moment it is not possible to change the return type or the controller.
Could you be able to tell me how to test this?
Change the response type to String as sketched below, and test for "true" "false" and it should work:
ResponseEntity<String> response = restTemplate.exchange(
createURLWithPort(url),
HttpMethod.GET, entity, String.class);