masiboo
masiboo

Reputation: 4719

How to mock RestTemplate in Springboot app

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

Answers (4)

SSK
SSK

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

TomStroemer
TomStroemer

Reputation: 1550

Your problem is the plantService = new PlantService(); You never inject into this selft created instance.

Solution 1

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.

Solution 2

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

fjsv
fjsv

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

Ahmed El-Gamal
Ahmed El-Gamal

Reputation: 190

You can do the following:

  1. Remove @RunWith annotation.

  2. Annontate your test class with @RestClientTest from org.springframework.boot.test.autoconfigure.web.client.RestClientTest.

  3. Use MockRestServiceServer from org.springframework.test.web.client.MockRestServiceServer.

  4. Mock the response of the server when being called in the test method, example:
@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

Related Questions