Reputation: 4719
This question has already been asked. The accepted answer doesn't work for me. Here is my code:-
My service is here:
@Service
public class PlantService {
@Autowired
RestTemplate restTemplate;
static String url = "http://some_url_?Combined_Name=Oak";
@Bean
public RestTemplate restTemplate(RestTemplateBuilder builder) {
return builder.build();
}
public String getJson() {
ResponseEntity<String> response = restTemplate.getForEntity(url, String.class);
return response.getBody();
}
}
My unit test
@RunWith(SpringRunner.class)
class PlantServiceTest {
private PlantService plantService;
@Mock
@Autowired
private RestTemplate restTemplate;
@Before
void setUp() {
MockitoAnnotations.initMocks(this);
plantService = new PlantService();
}
@Test
void testGetJsonString() {
// arrange
String expectedJson = "Some json string";
ResponseEntity mocResponse = mock(ResponseEntity.class);
// act
when(restTemplate.getForEntity("url", String.class)).thenReturn(mocResponse);
String actualJson = plantService.getJson();
// assert
assertSame(expectedJson, actualJson);
}
}
When I debug and step into the actual code. I can see restTemplate is null and throws java.lang.NullPointerException
. So how do I unit test this code?
Upvotes: 2
Views: 9060
Reputation: 3766
I have tried your code running on my machine.
Please find the test running test class
@RunWith(SpringRunner.class)
class PlantServiceTest {
@InjectMocks
private PlantService plantService;
@Mock
private RestTemplate restTemplate;
String url = "http://some_url_?Combined_Name=Oak";
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
}
@Test
void testGetJsonString() {
// arrange
String expectedJson = "Some json string";
ResponseEntity mocResponse = new ResponseEntity("Some json string", HttpStatus.OK);
// act
when(restTemplate.getForEntity(url, String.class)).thenReturn(mocResponse);
String actualJson = plantService.getJson();
// assert
assertSame(expectedJson, actualJson);
}
}
Upvotes: 2
Reputation: 1550
Your problem is the plantService = new PlantService();
You never inject into this selft created instance.
I usually do it like this:
@InjectMocks
private PlantService plantService = new PlantService();
@Mock
private RestTemplate restTemplate;
Remove the setup method and run with Mockito instead of the SpringRunner.
If you need the SpringRunner you can do the following:
@BeforeEach
void setUp() {
MockitoAnnotations.initMocks(this);
plantService = new PlantService();
ReflectionTestUtils.setField(plantService, "restTemplate", restTemplate);
}
As I've worked with JUnit 5 in the last years, I'm not sure about the SpringRunner. In JUnit 5 I can use both extensions (Spring and Mockito at the same time). Maybe this also worked in JUnit 4.
Upvotes: 0
Reputation: 714
You should use constructor injection in your PlantService
. For instance:
public class PlantService {
RestTemplate restTemplate;
@Autowired
public PlantService(RestTemplate restTemplate){
this.restTemplate = restTemplate;
}
}
And on your test you can just do:
plantService = new PlantService(restTemplate);
^^
yourMock
Upvotes: 0
Reputation: 190
You can do the following:
Remove @RunWith
annotation.
Annontate your test class with @RestClientTest
from org.springframework.boot.test.autoconfigure.web.client.RestClientTest
.
Use MockRestServiceServer
from org.springframework.test.web.client.MockRestServiceServer
.
@RestClientTest
public class MyTest {
@Autowired
private MockRestServiceServer server;
public void test() {
// setup
String expected = "test_value";
server.expect(requestToUriTemplate("/myendpoint"))
.andRespond(withSuccess(myJsonResponse, MediaType.APPLICATION_JSON));
// act
String actual = myClient.fetch(myRequestDto);
// assert
assertThat(actual, equalTo(expected));
server.verify();
}
}
I'm using assertThat
from hamcrest
, you can use whatever you want to assert the correctness of the result.
Upvotes: 0