How to mock WebClient.ResponseSpec, expecting response in pojo class list. code as below
public ResponseSpec externalAPICall(RequestBody requestBody) {
//ExternalApi
String url = "http://dev1:8080/external/api";
return client.post().uri(url).contentType(MediaType.APPLICATION_JSON)
.body(Mono.just(requestBody), RequestBody.class).retrieve();
}
tried to mock ResponseSpec with body, but getting NullPointerException
Related
I am trying to build the REST API JSON Media type using jersey also using jersey test framework for Junit testing.
I have create the GET Method and POST method, while doing JUnit test Get method works fine.
but when try to test the post method through JUnit test method POST Actual Method is not trigger.
Note: when I pass null here target("addresses").request().post(null); I can able to access the actual method. what goes wrong unable to find.
Test Method
#Test
public void testCreateAddressWithoutMandatoryFields() {
TestPojo addressRequest = new TestPojo();
addressRequest.setAddressId(333);
Entity<TestPojo> entiry = Entity.entity(addressRequest, MediaType.APPLICATION_JSON);
Response response = target("addresses").request().post(entiry);
assertEquals("Http Response should be 201 ", Status.CREATED.getStatusCode(), response.getStatus());
}
Actual Method
#POST
#Consumes(MediaType.APPLICATION_JSON)
#Produces(MediaType.APPLICATION_JSON)
public Response createAddress(#Context TestPojo addressRequest) {
try {
System.out.println("am i here" );
addressRequest.getAddressId();
}catch(Exception e) {
e.printStackTrace();
}
return Response.status(200).entity(null).build();
}
I'm using Spring Boot 2.5.6 and JUnit 4.13.2. My task is to test the DELETE method
My REST controller:
#RestController
public class DomainEndpoint {
private final SomeService service;
#DeleteMapping("/domain/{id}")
public void delete(#PathVariable long id) {
service.delete(id);
}
}
My test:
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#RunWith(SpringRunner.class)
public class DomainEndpointTest {
#Autowired
TestRestTemplate template;
#MockBean
SomeService service;
#Test
public void delete() {
String url = "/domain/123";
ResponseEntity<?> resp = template.exchange(url, HttpMethod.DELETE, new HttpEntity<>(""), String.class);
assertEquals(HttpStatus.NO_CONTENT, resp.getStatusCode());
}
}
As you can see, the only solution for testing the 'DELETE' method, which I found, is:
ResponseEntity<?> resp = template.exchange(url, HttpMethod.DELETE, new HttpEntity<>(""), String.class);
But params for body new HttpEntity<>("") and for return type String.class seem strange to me. Why should I use them? Can I do the same more straightway without passing unnecessary parameters?
On the other hand, TestRestTemplate template has a set of short and readable methods delete(). The problem with them - they return void and I can't check the response status code in this case.
The main question is how to test DELETE methods correctly?
Instead of passing in new HttpEntity<>("") HttpEntity has a special class variable you can use called HttpEntity.EMPTY for these situations. You can also use a return type of void.
ResponseEntity<Void> resp = template.exchange(url, HttpMethod.DELETE, HttpEntity.EMPTY, Void.class);
Two things you could improve:
Don't provide a request entity – it is marked as #Nullable
Use Void.class as return type to express that you don't expect any response body
ResponseEntity<Void> resp = restTemplate.exchange(url, HttpMethod.DELETE, null, Void.class);
Others have given different options but if you want to use the the delete method - it internally handles the http error by throwing runtime error as you can see here. You can check for HttpClientErrorException or HttpServerErrorException by using assertDoesNotThrow from JUnit5
In my opinion RestTemplate.delete method is the one to use, return type is void but status other than 2XX will throw an exception.
I am trying to mock an exchange call from a rest template but for some reason i am getting a null response from the call rather than the response entity i have specified in my test. Note - before adding the injectMocks on my service interface the rest template was trying to make an actual call, when i added that in it makes a mock call but with a null result.
#ActiveProfiles("unit-test")
#RunWith(SpringJUnit4ClassRunner.class)
#Category({ UnitTests.class })
#SpringBootTest#Import({PropertiesTestConfiguration.class})
public class MyTest {
#Mock
OAuth2RestTemplate serviceRestTemplate;
#Autowired
#InjectMocks
ServiceInterface serviceInterface;
#Test
public void getServiceResponse_Success() {
ResponseEntity<String> mockResponseEntity = new ResponseEntity<String>(mockResponseBody, HttpStatus.OK);
String url = "https://unit_test_/XXX";
UriComponentsBuilder builder = UriComponentsBuilder.fromHttpUrl(url);
Mockito.when(serviceRestTemplate.exchange( Matchers.anyObject(), Matchers.any(HttpMethod.class), Matchers.<HttpEntity> any(), Matchers.<Class<String>> any()) ).thenReturn(mockResponseEntity);
ServiceInterface.getClaimByClaimId(XXX);
}
}
In the method I am testing this returns null
responseEntity = serviceRestTemplate.exchange(uriBuilder.toUriString(),
method, requestEntity, String.class);
If you are using hamcrest matchers i will recommed to use is and isA methods to match the value or instance, this artical explains more about core matchers
Mockito.when(serviceRestTemplate.exchange(is(instanceOf(String.class)),
is(HttpMethod.GET),
is(HttpEntity.class),
isA(String.class)))
.thenReturn(mockResponseEntity);
I'm using MockMvc to test my method that has a date parameter. The parameter is annotated with #DateValid but MockMvc doesn't trigger the validator and returns success when I input a wrong date.
StudentControler
public ResponseEntity<?> getStudents(#PathVariable("id") String studentId,
#RequestParam("birthDate") #DateValid String Date) {
//do something
}
Test
public class StudentController extends AbstractControllerTest {
#Test
public void testStudents_validRequest() throws Exception {
MultiValueMap<String, String> params = new LinkedMultiValueMap<>();
params.add("birthDate","aaaa");
MvcResult result = getMvc().perform(get("/student/{studentId}", "test")
.params(params)
.characterEncoding(StandardCharsets.UTF_8.name())
.contentType(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().json(mapToJson(studentResDto)))
.andReturn();
verify(studentService).getStudentId(anyString(), anyString());
log(log, result);
}
}
I do not understand why because when I test using Postman it works as expected. Postman does validate but MockMvc does not?
I using Spring-Boot 2.1.3
I can think of 2 problems here:
The validation annotation class is not loaded properly in your test. This seems to happen primarily when combining Spring validation with Hibernate validation (see also this question on how to fix that.
Your test is not setup properly. Could it be that you are not fully loading your controller in your mock test? Perhaps you are mocking the controller accidentally?
In my integration test, I tried to use resttemplate to send a Get request to a dummy server created by MockMvcBuilders. However I got an error:
I/O error on GET request for "http://localhost:8080/test":Connection refused:
(In the function testAccess(), url is "http://localhost:8080/test"). My code is as below:
#RunWith(SpringJUnit4ClassRunner.class)
#WebAppConfiguration
#IntegrationTest("server.port=8080")
public class MyTest {
private MockMvc mockMvc = null;
#Autowired
private WebApplicationContext context;
#Value("${server.port}")
private int port;
#Autowired
private MyController myController;
#Before
public void setUp(){
mockMvc = MockMvcBuilders.webAppContextSetup(context)
.build();
}
#Test
public void testAccess() throws Exception{
RestTemplate restTemplate=new RestTemplate();
String url="http://localhost:8080/test";
try{
ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, null, String.class);
}
catch(ResourceAccessException ex){
System.out.println(ex.getMessage());
}
}
#Controller
public static class MyController {
#RequestMapping(value = "/test", method = RequestMethod.GET)
public #ResponseBody String access() {
return "OK";
}
}
}
The way I've done it is this:
First, you create a mock server from the actual RestTemplate you are using in your application
#Before
public void setup() throws Exception {
mockServer = MockRestServiceServer.createServer(myService.restTemplate);
}
Then you define how that request is going to work:
mockServer.expect(requestTo("http://localhost:8080/myrestapi"))
.andExpect(method(HttpMethod.POST))
.andRespond(withSuccess("{ success: true }", MediaType.APPLICATION_JSON));
And last you call the method in your application that will trigger a call to that url with that RestTemplate:
#Test
public void testThis() throws Exception {
myService.somethingThatCallsMyRestApi(parameters);
}
That will make your tests work as if there was a server up and running to process requests.
Using this in your example makes no sense, cause you would be testing that you build your test correctly and nothing else from the actual application.
The problem with this is that you cannot test dynamic responses. I mean, in my case the method I'm calling generates different data every time you call it and then sends it to the mockServer and then validates that the response matches in some very specific way. I haven't found a solution yet, but if the data you are going to send and receive is previously known, which would be in most cases, you'll have no problem using this.
Why are you defining a controller in your Test class and then trying to test it ? It doesn't feel logical to try to test something that is defined within the test it self.
Rather you would want to test a controller defined somewhere outside your tests, an actual controller that is used within your application.
Let's say MyController is defined as an actual controller then you could use the mockMvc object you created to test it.
mockMvc.perform(get('/test'))
.andExpect(status().isOk())