模拟方法返回NullPointerException

时间:2019-09-17 11:42:00

标签: java unit-testing junit mockito junit5

我想测试一种将标头添加到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对象没有模拟的事实有关。如果是真的,我将不胜感激为您提供有关如何解决此问题的建议。

1 个答案:

答案 0 :(得分:2)

您需要使用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();
}