Search code examples
javaunit-testingjunitresttemplate

ResourceAccessException: I/O error on POST request


I have a service method. The method is accessing a third-party resource through a POST request. I am writing a test and I see an error in the logs. Service:

@Override
public void sendDoc(String id) throws IOException {
    byte[] zipData = getZipFromIntegration(mongo.getDocument());

    String response;
    HttpStatus httpStatus;
    try {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.MULTIPART_FORM_DATA);

        LinkedMultiValueMap<String, Object> map = new LinkedMultiValueMap<>();
        map.add("file", new MultipartInputStreamFileResource(new ByteArrayInputStream(zipData),
                String.format("%s_some.zip", id)));

        HttpEntity<LinkedMultiValueMap<String, Object>> requestEntity = new HttpEntity<>(map, headers);

        HttpComponentsClientHttpRequestFactory clientHttpRequestFactory = new HttpComponentsClientHttpRequestFactory();
        clientHttpRequestFactory.setConnectTimeout(3000);
        clientHttpRequestFactory.setReadTimeout(3000);
        RestTemplate restTemplate = new RestTemplate(clientHttpRequestFactory);

        response = restTemplate.postForObject(uploadUrl + system,
                requestEntity, String.class);

    } catch (HttpStatusCodeException e) {
        LOG.error("Some error");
    }
}

My Test

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = NONE, classes = {SendServiceImpl.class})
@EnableAutoConfiguration
@PropertySource(value = "classpath:application.properties", encoding = "UTF-8")
public class SendServiceImplTest {
    @MockBean
    private RestTemplate restTemplate;
    @Autowired
    private SendServiceImpl service;

    @Test
    public void sendDoc() throws IOException {
        when(restTemplate.postForObject(
                anyString(),
                ArgumentMatchers.<HttpEntity<?>>any(),
                ArgumentMatchers.<Class<String>>any()
        ))
                .thenReturn("ok");

        service.sendDoc("55454545uid");
    }
}

But I see that there is a call to the real server. The test is successful, but in the logs I see an error:

org.springframework.web.client.ResourceAccessException: I/O error on POST request for "http://some-url.digital.cloud.ru/v1/doc/reg"

UPD: Changed the test like this:

@RunWith(PowerMockRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK, classes = SendServiceImpl.class)
@PowerMockRunnerDelegate(SpringRunner.class)
@PrepareForTest({SendServiceImpl.class, RestTemplate.class})
@PowerMockIgnore({"javax.xml.*", "org.xml.sax.*", "org.w3c.dom.*"})
public class SendServiceImplTest {
    @MockBean
    private RestTemplate restTemplateMock;

    @Autowired
    private SendServiceImpl service;

    @Test
    public void sendDoc() throws IOException {
    RestTemplate restTemplate = PowerMockito.mock(RestTemplate.class);
    whenNew(RestTemplate.class).withArguments(ClientHttpRequestFactory.class).thenReturn(restTemplate);
    when(restTemplate.postForObject(
                anyString(),
                ArgumentMatchers.<HttpEntity<?>>any(),
                ArgumentMatchers.<Class<String>>any()
        ))
                .thenReturn("ok");

        service.sendDoc("55454545uid");
    }
}

Now the object is replaced by null. That is, restTemplate in the service is null.


Solution

  • The solution to my problem looks like this:

    @RunWith(PowerMockRunner.class)
    @SpringBootTest(webEnvironment = NONE, classes = SendServiceImpl.class)
    @PowerMockRunnerDelegate(SpringRunner.class)
    @PrepareForTest({
            SendServiceImpl.class,
            RestTemplate.class,
            HttpComponentsClientHttpRequestFactory.class
    })
    @MockBean({FileStorageService.class, DocxToPdfConverterService.class})
    @PowerMockIgnore({"javax.xml.*", "org.xml.sax.*", "org.w3c.dom.*"})
    public class SendServiceImplTest {
        @Test
        public void sendDoc() throws Exception {
            RestTemplate restTemplate = Mockito.mock(RestTemplate.class);
    
            whenNew(RestTemplate.class).withAnyArguments().thenReturn(restTemplate);
    
            PowerMockito.when(restTemplate.postForObject(
                    anyString(),
                    ArgumentMatchers.<HttpEntity<?>>any(),
                    ArgumentMatchers.<Class<String>>any()
            )).thenReturn("ok");
        }
    // ......any code.......
    }
    

    The PowerMock library and the withAnyArguments () method helped me.