Reputation: 2072
Actually I am trying to do UT of bellow method :
@Override
public Reservation findReservation(Long id) {
RestTemplate restTemplate = new RestTemplate();
Reservation reservation = restTemplate.getForObject(RESERVATION_REST_URL+id, Reservation.class);
return reservation;
}
I am doing UT as bellow :
@Before
public void setUp(){
MockitoAnnotations.initMocks(this);
}
@Test
public void testFindReservation(){
Reservation reservation = new Reservation();
reservation.setId(1000l);
reservation.setCheckiIn(true);
reservation.setNumberOfBags(10);
when(restTemplate.getForObject("http://localhost:8080/flightreservation/reserva
tions/1000", Reservation.class))
.thenReturn(reservation);
Reservation res = reservationRestClient.findReservation(1000l);
Assert.assertNotNull(res);
}
But it gives error, As per my understanding its not mocked properly, Somehow RestTemplate is trying to call real api rather than mock.
ResourceAccessException: I/O error on GET request for http://localhost:8080/flightreservation/reserva
tions/1000
Service class :-
@Service
public class ReservationRestServiceImpl implements ReservationRestService {
private static final String RESERVATION_REST_URL = "http://localhost:8080/flightreservation/reservations/";
private final RestTemplate restTemplate;
public ReservationRestServiceImpl(RestTemplateBuilder restTemplateBuilder) {
this.restTemplate = restTemplateBuilder.build();
}
@Override
public Reservation fetchReservationByPnr(Long id) {
Reservation reservation = restTemplate.getForObject(RESERVATION_REST_URL+id, Reservation.class);
return reservation;
}
}
And Test File is as bellow, After Mocking RestTemplateBuilder In testfile, It gives NLP.
@RunWith(SpringRunner.class)
//@AutoConfigureWebClient
@SpringBootTest(classes = { WebcheckinApplication.class })
public class WebcheckinApplicationTests {
private ReservationRestServiceImpl reservationRestServiceImpl;
@Mock
private RestTemplateBuilder restTemplateBuilder;
@Before
public void setUp() throws Exception {
reservationRestServiceImpl = new ReservationRestServiceImpl();
MockitoAnnotations.initMocks(this);
}
@Test
public void contextLoads() {
}
@Test
public void testFindReservation(){
Reservation reservation = new Reservation();
reservation.setId(1000l);
reservation.setCheckiIn(true);
reservation.setNumberOfBags(10);
RestTemplateBuilder builder = mock(RestTemplateBuilder.class);
reservationRestServiceImpl.setBuilder(builder);
reservationRestServiceImpl.init();
when(builder.build().getForObject("http://localhost:8080/flightreservation/reservations/1000", Reservation.class))
.thenReturn(reservation);
Reservation res = reservationRestServiceImpl.fetchReservationByPnr(1000l);
Assert.assertNotNull(res);
//assertEquals("{message : 'under construction'}", result);
}
}
Upvotes: 1
Views: 4467
Reputation: 5003
I'm not sure what version of Spring you are using. However the recommended pattern in Spring is to use a RestTemplateBuilder instead of creating a RestTemplate directly
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-resttemplate.html
A RestTemplateBuilder would be injected into the service, and the rest template constructed from it. In your test case, you can inject a Mocked RestTemplateBuilder which can, in turn, return a mocked RestTemplate.
So, if you have the ability to refactor the original service, you can have some code that is much more testable.
--More Details--
This is how I would set up the class...
public class SomeService {
private RestTemplateBuilder builder;
private RestTemplate restTemplate;
@Autowired
public void setBuilder(RestTemplateBuilder builder) {
this.builder = builder;
}
@PostConstruct
public void init() {
restTemplate = builder.build();
}
public Object fetchReservationByPnr(Long id) {
return restTemplate.getForObject("someUrl"+id, Object.class);
}
}
Then, in your test, you can just create the service, assign a Mocked RestTemplateBuilder and call init. You won't need the Spring runner or run up the test in a Spring Context. The standard JUnit runner will suffice.
I haven't completely done your test, but this works for me
import org.junit.Test;
import org.mockito.Mockito;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.web.client.RestTemplate;
public class SomeServiceTest {
@Test
public void testMe() {
RestTemplateBuilder mockedBuilder = Mockito.mock(RestTemplateBuilder.class);
RestTemplate mockedRestTemplate = Mockito.mock(RestTemplate.class);
Mockito.when(mockedBuilder.build()).thenReturn(mockedRestTemplate);
SomeService someService = new SomeService();
someService.setBuilder(mockedBuilder);
someService.init();
Mockito.verify(mockedBuilder).build();
}
}
For your test, simply add additional mocks to the mocked RestTemplate
Upvotes: 1
Reputation: 497
@Sandeep Tiwari..make your test case set up like this ...
@Autowired
private MockRestServiceServer server;
@Autowired
private RestTemplate restTemplate;
add these following in @Before method ....
------------------------------------
server.expect(ExpectedCount.manyTimes(), requestTo(URL)).andRespond(withSuccess(detailsString, MediaType.APPLICATION_JSON));
Upvotes: 1