Mocked method returning NullPointerException

Martin :

I want to test a method which will add headers to my GET request in order to establish a connection with public API. My service with business logic looks like:

@Service
public class RestTemplateFacade {

  private NutritionixHeader nutritionHeaderParam;
  private RestTemplate restTemplate;

  public RestTemplateFacade(
      NutritionixHeader nutritionHeaderParam,
      RestTemplate restTemplate) {
    this.nutritionHeaderParam = nutritionHeaderParam;
    this.restTemplate = restTemplate;
  }

  public ResponseEntity<Products> addHeaderToRequest(String queryParam) {

    HttpHeaders headers = new HttpHeaders();
    headers.set("x-app-id", nutritionHeaderParam.getNutritionixAppId());
    headers.set("x-app-key", nutritionHeaderParam.getNutritionixAppKey());

    UriComponentsBuilder uriBuilder = UriComponentsBuilder
        .fromHttpUrl("https://trackapi.nutritionix.com/v2/search/instant")
        .queryParam("query", queryParam);

    HttpEntity httpEntity = new HttpEntity(headers);

    return
        restTemplate
            .exchange(
                uriBuilder.toUriString(),
                HttpMethod.GET,
                httpEntity,
                Products.class);
  }
}

NutritionixHeader.class looks like:

@PropertySource("classpath:nutritionix.properties")
@Configuration
@Getter
@NoArgsConstructor
public class NutritionixHeader {

    @Value("${nutritionix-app-id}")
    private String NutritionixAppId;

    @Value("${nutritionix-app-key}")
    private String NutritionixAppKey;
}

My test class looks like:

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class RestTemplateFacadeTest {

  @Mock
  private NutritionixHeader nutritionixHeader;

  @Mock
  private RestTemplate restTemplate;

  @InjectMocks
  private RestTemplateFacade restTemplateFacade;

  @Mock
  private UriComponentsBuilder uriComponentsBuilder;

  @BeforeEach
  void setUp() {
    restTemplateFacade = new RestTemplateFacade(nutritionixHeader, restTemplate);
  }

  @Test
  void addHeaderToRequest() {

    //given
    var query = "query";
    given(nutritionixHeader.getNutritionixAppId()).willReturn("x-app-id");
    given(nutritionixHeader.getNutritionixAppKey()).willReturn("x-app-key");

    //when
    ResponseEntity<Products> productsResponse = restTemplateFacade.addHeaderToRequest(query);
    HttpHeaders headers = productsResponse.getHeaders();

    //then
    assertEquals("x-app-id",
        headers.entrySet()
            .stream()
            .filter(entry -> entry.getKey().equals("x-app-id"))
            .map(Entry::getValue)
            .flatMap(Collection::stream)
            .findFirst()
            .orElse(""));

    then(nutritionixHeader).should(times(1)).getNutritionixAppId();
  }

Problem occurs in the line:

HttpHeaders headers = productsResponse.getHeaders();

with NullPointerException.

All I need is the ability to test if my method has correctly added headers to my GET query.

I am a little bit confused because it seems that I mocked everything properly but still receiving null pointer. Maybe my NPE is related to the fact there is no mock for my RestTemplate object. If it's true I will be grateful for suggestions on how to fix this problem.

i.bondarenko :

You need use ArgumentCaptor to catch HttpEntity and then get the headers. Have a look at the code:

@Test
void addHeaderToRequest() {

    //given
    var query = "query";
    given(nutritionixHeader.getNutritionixAppId()).willReturn("x-app-id");
    given(nutritionixHeader.getNutritionixAppKey()).willReturn("x-app-key");

    //when
    restTemplateFacade.addHeaderToRequest(query);

    //then

    ArgumentCaptor<HttpEntity> httpEntityCapture = ArgumentCaptor.forClass(HttpEntity.class);
    String url = "https://trackapi.nutritionix.com/v2/search/instant?query=query";
    verify(restTemplate).exchange(eq(url), eq(HttpMethod.GET), httpEntityCapture.capture(), eq(Products.class));

    HttpHeaders headers = httpEntityCapture.getValue().getHeaders();

    assertEquals("x-app-id",
            headers.entrySet()
                    .stream()
                    .filter(entry -> entry.getKey().equals("x-app-id"))
                    .map(Map.Entry::getValue)
                    .flatMap(Collection::stream)
                    .findFirst()
                    .orElse(""));

    then(nutritionixHeader).should(times(1)).getNutritionixAppId();
}

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326582&siteId=1