Издевательский метод, возвращающий NullPointerException

Я хочу протестировать метод, который добавит заголовки в мой запрос GET, чтобы установить соединение с общедоступным API. Мой сервис с бизнес-логикой выглядит так:

@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 выглядит так:

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

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

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

Мой тестовый класс выглядит так:

@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();
  }

Проблема возникает в строке:

HttpHeaders headers = productsResponse.getHeaders();

с NullPointerException.

Все, что мне нужно, — это возможность проверить, правильно ли мой метод добавил заголовки в мой запрос GET.

Я немного смущен, потому что кажется, что я все правильно издевался, но все еще получаю нулевой указатель. Возможно, мой NPE связан с тем, что для моего объекта RestTemplate нет макета. Если это правда буду признателен за предложения по устранению этой проблемы.


person Martin    schedule 17.09.2019    source источник


Ответы (1)


Вам нужно использовать ArgumentCaptor, чтобы поймать HttpEntity, а затем получить заголовки. Взгляните на код:

@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();
}
person i.bondarenko    schedule 17.09.2019
comment
Большое спасибо за быстрый ответ. Это работает отлично. - person Martin; 17.09.2019
comment
Я рад помочь! - person i.bondarenko; 17.09.2019