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.
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.