unable to hit on url using RestTemplate in Junit Test - spring-boot

I am not able to run the restTemplate whenever I run the unit test. Is there anything I need to set in the Unit Test class?
http://localhost:8082/test is another program running, whenever I run the unit test, it will get stuck at the restTemplate.postForEntity and keep rolling. Can anyone advise?
I don't wish to mock http://localhost:8082/test
Below is my source code.
UserService.java
#Service
public class UserService{
public void processUserInfo(User user){
HttpHelperService service = new HttpHelperService();
service.callOthers();
}
}
HttpHelperService.java
#Service
public class HttpHelperService{
#Autowired
RestTemplate restTemplate;
String url = "http://localhost:8082/test"
public void callOthers(){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.MULTIPART_FORM_DATA);
MultiValueMap<String, Object> body = new MultiValueMap<String, Object>();
body.add("param1", "test");
body.add("param2", "test1234");
HttpEntity<MultiValueMap<String, Object>> requestEntity = new HttpEntity<>(body, headers);
restTemplate.postForEntity(url, requestEntity, String.class); //when run the unit test (AppTest), it will get stuck here.
}
}
My unit test below
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.DEFINED_PORT)
public class AppTest{
#Autowired
UserService userService;
#Test
public void test1(){
userService.processUserInfo();
}
}

Related

How to correctly mock Interceptor pre handle method in spring boot integration tests

I'm writing an integration test to an API which receives #RequestAttribute List<String> permissions and HttpServletRequest request as method parameters. There is a custom interceptor which overrides the preHandle() method of HandlerInterceptor. This method receives HttpServletRequest request and HttpServletResponse response as parameters. Based on some logic there are some attributes set in HttpServletRequest request.
I'm writing an integration test where in I send an Http request to the endpoint of the application. I want to mock the interceptor and set these attributes myself.
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#RunWith(SpringRunner.class)
public class TradeChargesTest {
#LocalServerPort
public int port;
#MockBean
AppInterceptor interceptor;
// other stuff
#BeforeEach
void initTest() throws Exception {
// Want to write the mock interceptor logic here.
}
public TestRestTemplate restTemplate = new TestRestTemplate();
public String createURLWithPort(String uri) {
return "http://localhost:" + port + uri;
}
}
Test method:
public class UserInfoControllerTest extends TradeChargesTest {
TestRestTemplate restTemplate = new TestRestTemplate();
HttpHeaders headers = new HttpHeaders();
#Test
public void testUserInfoController(){
HttpEntity<String> entity = new HttpEntity<String>(null, headers);
ResponseEntity response = restTemplate.exchange(createURLWithPort("Testing/endpoint/user/v5/getUser?from_date=2022-04-01&page=1"), HttpMethod.GET, entity, Object.class);
assertEquals(200, response.getStatusCodeValue());
LinkedHashMap<String, Object> responseBodyMap = (LinkedHashMap<String, Object>) response.getBody();
assertEquals(3, responseBodyMap.get("totalHits"));
assertEquals(1, responseBodyMap.get("page"));
}
}

unable to mock RestTemplate response

I wanted to mock the RestTemplate's result, but with my code below, it always went to do the Http. Can someone please advise? I think I have parts that I did wrongly, please help.
UserServiceTest.java
#RunWith(SpringJUnit4ClassRunner.class)
public class UserServiceTest(){
#InjectMock
#Autowired
UserService userservice;
#Mock
RestTemplate restTemplate;
#Value(${aa.bb.cc})
private String getfromapplicationpropertiesVal;
#Test
public void test1(){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String jsonBody = null;
HttpEntity<String> entity = new HttpEntity<>(jsonBody, headers);
String textContent = "result from junit";
ResponseEntity<String> response = new ResponseEntity<>(textContent, HttpStatus.OK);
String url = "http://localhost:8080/test/test.txt";
doReturn(response).when(restTemplate).exchange(
eq(url),
any(HttpMethod.class),
any(HttpEntity.class),
any(Class.class)
);
userservice.test();
}
}
UserService.java
#Service
public class UserService{
#Autowired
HttpHelperService httpHelperService;
public void test(){
String url = "http://localhost:8080/test/test.txt";
String response = httpHelperService.cal(url, HttpMethod.GET);
System.out.println(response);
}
}
HttpHelperService.java
#Service
public class HttpHelperService{
#Autowired
private RestTemplate restTemplate;
public String cal(String url, HttpMethod httpMethod){
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
String jsonBody = null;
HttpEntity<String> entity = new HttpEntity<>(jsonBody, headers);
String response = restTemplate.exchange(url, httpMethod, entity, String.class); //This part kept calling http when run the #Test
}
}
RestTemplateConfig
#Configuration
public class RestTemplateConfig{
#Bean
public RestTemplate restTemplate(){
return new RestTemplate();
}
}
Recommendation in these type of scenario is to use MockRestServiceServer & not mocking restTemplate.
You might do something like this:
#Mock
RestTemplate restTemplate;
#Autowired
MockRestServiceServer mockServer;
#BeforeEach
public void init(){
mockServer = MockRestServiceServer.createServer(restTemplate); //initialization
}
And then invoke mock for your service something like :
mockServer.expect(requestTo(url))
.andExpect(method(HttpMethod.GET))
.andRespond(withSuccess("successOperation"));
-Alternatively, you can just mock your test() method:
when(mockedHttpHelperService).cal(anyString(),HttpMethod.GET).thenReturn("success");

How to mock a RestTemplate Exchange spring boot

I have tried many ways to mock the restTemplate exchange, but the mock is not happening, the actual exchange keeps on calling and gives me url not valid exception.
My CallRestService method is below
public class Util{
public static ResponseEntity<String> callRestService(JSONObject reqJsonObj,HttpHeaders headers, String url, HttpMethod method, boolean isAuto){
ResponseEntity<String> re=null;
try{
HttpEntity<String> entity=null;
entity=new HttpEntity<>(String.valueOf(reqJsonObj),headers);
RestTemplate restTemplate= new RestTemplate();
re=restTemplate.exchange(url,method,entity,String.class);
}catch(Exception e){
System.out.println(e);
}
}
}
And My Mock is below:
public class UtilTest{
#InjectMocks
Util util;
#Mock
RestTemplate restTemplate;
ResponseEntity res=mock(ResponseEntity.class);
#Test
public void test(){
//ResponseEntity<String> entity=new ResponseEntity<String>("anySt",HttpStatus.ACCEPTED);
Mockito.when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(HttpEntity.class),
ArgumentMatchers.<Class<String>>any())
).thenReturn(res);
Util.callRestService(json,headers,url,HttpMethod.POST,false);
}
}
I also tried to return the commented response Entity. but always got exception in exchange.
What i understand about mocking is the actual exchange method will not be called, then how am i getting resttemplate exchange exception.
if any inputs required pls comment.
Thanks for the support.
UPDATE:
I tried with changing the static method to non static but kept the test case as is. But i get the same error
The problem is resolved when I update the method to non static and move the Resttemplate declaration outside the method.
Updated code is below, if anyone found it useful.
Method changes :
public class Util{
private RestTemplate restTemplate= new RestTemplate();
public ResponseEntity<String> callRestService(JSONObject reqJsonObj,HttpHeaders headers, String url, HttpMethod method, boolean isAuto){
ResponseEntity<String> re=null;
try{
HttpEntity<String> entity=null;
entity=new HttpEntity<>(String.valueOf(reqJsonObj),headers);
re=restTemplate.exchange(url,method,entity,String.class);
}catch(Exception e){
System.out.println(e);
}
}
}
And the mock with verify :
public class UtilTest{
#InjectMocks
Util util;
#Mock
RestTemplate restTemplate;
#Test
public void test(){
ResponseEntity<String> entity=new ResponseEntity<String>("anySt",HttpStatus.ACCEPTED);
Mockito.when(restTemplate.exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(HttpEntity.class),
ArgumentMatchers.<Class<String>>any())
).thenReturn(entity);
Util.callRestService(json,headers,url,HttpMethod.POST,false);
Mockito.verify(restTemplate,times(1)).exchange(
ArgumentMatchers.anyString(),
ArgumentMatchers.any(HttpMethod.class),
ArgumentMatchers.any(HttpEntity.class),
ArgumentMatchers.<Class<String>>any())
)
}
}

How to mock resttemplate calls in spring boot?

I tried to write test cases for the rest calls in my service which is calling the 3rd party api.
#RunWith(MockitoJUnitRunner.class)
public class ForceServiceTest {
private ForceService forceService;
#Mock
private ForceServiceConfig config;
#Mock
private RestTemplate restTemplate;
#Before
public void setup() {
forceService = new ForceService(config);
}
#Test
public void apiCall_valid() throws JSONException {
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(
"id=null",
headers);
config.authTokenUrl = "https://ex...com/..";
Mockito.when(restTemplate.exchange(config.authTokenUrl, HttpMethod.POST, entity, Access.class)).thenReturn(null);
// Mockito.when(any()).thenReturn(null);
forceService.apiCall();
}
}
#Component
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate = new RestTemplate();
public ForceService(ForceServiceConfig config) {
this.config = config;
}
private String apiCall() {
HttpHeaders headers = new HttpHeaders();
headers.set(CONTENT_TYPE, "application/x-www-form-urlencoded");
headers.set(ACCEPT, APPLICATION_JSON);
HttpEntity<String> entity = new HttpEntity<>(
"&id=" + config.id,
headers);
ResponseEntity<Access> response = restTemplate.exchange(config.authTokenUrl, HttpMethod.POST, entity,
Access.class);
return response.getBody().token_type + " " + response.getBody().access_token;
}
}
I get the following error:
org.springframework.web.client.HttpClientErrorException: 404 Not Found
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:78)
at org.springframework.web.client.RestTemplate.handleResponse(RestTemplate.java:700)
at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:653)
It is calling the api in test class, which I do not want to happen.
I need to mock the resttemplate call of 3rd party api. How can I do it without being actually calling the api?
This is the problem
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate = new RestTemplate(); // HERE
you are creating new REAL rest template. What you probably want is to
Use mock that you created in wrapping test class
Use real rest template and SPY on it.
A don't know is that your actualy structure (1 file 2 classes) but it is safe to assume it is not and in any case you can simply pass RestTemplate as ctor argument. So
#Component
public class ForceService {
private ForceServiceConfig config;
private RestTemplate restTemplate;
public ForceService(ForceServiceConfig config,RestTemplate restTemplate) {
this.restTemplate=restTemplate;
this.config = config;
}
and
#Before
public void setup() {
forceService = new ForceService(config,restTemplate);
}
Now if you want to RestTemplate to be just a stub that does literally nothing and return null on any calls if not instructed otherwiser - leave it as #Mock.
If you want however, to allow it to work normally and only intercept some specific method calls and stub responses, use spy.
#Mock
private RestTemplate restTemplate;
private RestTemplate restTemplate=Mockito.mock(RestTemplate.class)
or
private RestTemplate restTemplate=Mockito.spy(new RestTemplate());

How to Mock client side rest service

I'm trying to create mockito test run for rest api below is the controller class followed by mock test which I'm trying to execute but the problem is it is still calling actual rest api instead of mocking it,
1) Controller Class
public void sendData(ID id, String xmlString, Records record) throws ValidationException{
ClientHttpRequestFactory requestFactory = new
HttpComponentsClientHttpRequestFactory(HttpClients.createDefault());
RestTemplate restTemplate = new RestTemplate(requestFactory);
List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
messageConverters.add(new StringHttpMessageConverter(Charset.forName("UTF-8")));
restTemplate.setMessageConverters(messageConverters);
MultiValueMap<String,String> header = new LinkedMultiValueMap<>();
header.add("x-api-key",api_key);
header.add("Content-Type",content_type);
header.add("Cache-Control",cache_control);
HttpEntity<String> request = new HttpEntity<>(xmlString, header);
try {
restTemplate.postForEntity(getUri(id,record), request, String.class);
}catch (RestClientResponseException e){
throw new ValidationException("Error occurred while sending a file to some server "+e.getResponseBodyAsString());
}
}
2) Test class
#RunWith(MockitoJUnitRunner.class)
public class Safe2RestControllerTest {
private MockRestServiceServer server;
private RestTemplate restTemplate;
private restControllerClass serviceToTest;
#Before
public void init(){
//some code for initialization of the parameters used in controller class
this.server = MockRestServiceServer.bindTo(this.restTemplate).ignoreExpectOrder(true).build();
}
#Test
public void testSendDataToSafe2() throws ValidationException, URISyntaxException {
//some code here when().then()
String responseBody = "{\n" +
" \"responseMessage\": \"Validation succeeded, message
accepted.\",\n" +
" \"responseCode\": \"SUCCESS\",\n" +
" 2\"responseID\": \"627ccf4dcc1a413588e5e2bae7f47e9c::0d86869e-663a-41f0-9f4c-4c7e0b278905\"\n" +
"}";
this.server.expect(MockRestRequestMatchers.requestTo(uri))
.andRespond(MockRestResponseCreators.withSuccess(responseBody,
MediaType.APPLICATION_JSON));
serviceToTest.sendData(id, xmlString, record);
this.server.verify();
}
}
How should I go ahead, any suggestion would be appreciated.
Spring's MVC test apparatus makes this quite easy.
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = YourController.class)
public class YourControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
public void testSendDataToSafe2() throws Exception {
// prepare e.g. create the requestBody
MvcResult mvcResult = mockMvc.perform(post(uri).contentType(MediaType.APPLICATION_JSON).content(requestBody))
.andExpect(status().isOk())
.andReturn();
Assert.assertEquals(responseBody, mvcResult.getResponse().getContentAsString());
}
}
For more details, see the section titled "Add Unit Tests" here and/or the section titled "Auto-configured Spring MVC tests" here.
Your question also states "the problem is it is still calling actual rest api" so I'm guessing that, in addition to calling your controller is a test context, you want that mock out some of the behaviour of that controller. Specifically, you want to mock the RestTemplate instance used in that controller. If so, then would have to change the controller implementation such that the RestTemplate instance is an #Autowired class member. Then you would declare a mock for that in your test case like so:
#RunWith(SpringRunner.class)
#WebMvcTest(controllers = YourController.class)
public class YourControllerTest {
#Autowired
private MockMvc mockMvc;
#MockBean
private RestTemplate restTemplate;
#Test
public void testSendDataToSafe2() throws Exception {
// prepare e.g. create the requestBody
// tell your mocked RestTemplate what to do when it is invoked within the controller
Mockito.when(restTemplate.postForEntity(..., ..., ...)).thenReturn(...);
MvcResult mvcResult = mockMvc.perform(post(uri).contentType(MediaType.APPLICATION_JSON).content(requestBody))
.andExpect(status().isOk())
.andReturn();
Assert.assertEquals(responseBody, mvcResult.getResponse().getContentAsString());
}
}
The above code is valid for spring-test:4.3.10.RELEASE.

Resources