Весеннее тестирование веб-клиента с помощью веб-сервера okhttp3

#spring-boot #okhttp #spring-webclient

Вопрос:

Я не могу отключить веб-клиент

WebClientConfig.java

 public @Bean("oauthWebClient") WebClient oauthWebClient() {

    return WebClient.builder()
            .clientConnector(new ReactorClientHttpConnector(
                    HttpClient.create().option(ChannelOption.CONNECT_TIMEOUT_MILLIS, 1000)
                            .doOnConnected(connection -> connection.addHandlerLast(new ReadTimeoutHandler(10))
                                    .addHandlerLast(new WriteTimeoutHandler(10)))))
            .filter(logOAuthResponse()).baseUrl(oauthTokenUrl)

            .defaultHeaders(headers -> {

                headers.setBasicAuth(secretHeaderValue);
                headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_FORM_URLENCODED_VALUE);

            })

            .defaultUriVariables(oauthUriVariables)

            .build();
}
 

serviceUti.java
пакет com.test.stats.volts.busops.utils;

         import java.util.Map;

        import org.slf4j.Logger;
        import org.slf4j.LoggerFactory;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.beans.factory.annotation.Qualifier;
        import org.springframework.beans.factory.annotation.Value;
        import org.springframework.http.HttpStatus;
        import org.springframework.http.MediaType;
        import org.springframework.http.ResponseEntity;
        import org.springframework.retry.annotation.Recover;
        import org.springframework.retry.annotation.Retryable;
        import org.springframework.stereotype.Component;
        import org.springframework.web.reactive.function.client.WebClient;
        import org.springframework.web.reactive.function.client.WebClientRequestException;
        import org.springframework.web.reactive.function.client.WebClientResponseException;

        import com.fasterxml.jackson.core.JsonProcessingException;
        import com.fasterxml.jackson.databind.ObjectMapper;
        import com.fasterxml.jackson.databind.node.ObjectNode;
        import com.test.stats.volts.busops.exception.VoltsDataAccessException;
        import com.test.stats.volts.busops.exception.MtnDataAccessNotRespondingException;
        import com.test.stats.volts.busops.exception.VoltsDataAcessException;
        import com.test.stats.volts.busops.exception.UnableToGetOAuthTokenException;


        @Component("voltsDataAccessServiceUtil")
        public class ServiceUtil {

            private static final Logger logger = LoggerFactory.getLogger(ServiceUtil.class);

            @Autowired
            @Qualifier("voltsDataAccessWebClient")
            WebClient voltsDataAccessClient;

            @Autowired
            @Qualifier("oauthWebClient")
            WebClient oauthClient;

            @Value("${volts.dataaccess.end.point.save-meeting}")
            private String saveMeetingEndPoint;

            @Value("${volts.dataaccess.oauth.header-key.name}")
            private String oauthHeaderKeyName;

            @Value("${volts.dataccess.oauth.response.token.key-name}")
            private String oauthResponseTokenKeyName;

            @Value("#{${volts.dataaccess.api.endpoints.default.uri-variables}}")
            private Map<String, String> voltsDataAccessUriVariables;

            @Autowired
            ObjectMapper mapper;

            @Value("#{${volts.dataaccess.oauth.uri-variables}}")
            private Map<String, String> oauthUriVariables;

            @Value("${volts.dataaccess.oauth.scope}")
            private String oauthScope;

            @Value("${volts.dataaccess.oauth.grant_type}")
            private String grantType;

            @Value("${volts.dataaccess.oauth.secret.header-name}")
            private String secretHeaderName;

            @Value("${volts.dataaccess.oauth.secret.header-value}")
            private String secretHeaderValue;

            @Value("${volts.dataaccess.end.point.fetch-meeting}")
            private String fetchMeetingEndPoint;

            @Value("${volts.dataaccess.query.param.api-key-value}")
            private String apiKey;

            @Retryable(maxAttempts = 2)
            public String postOAuthToken() throws VoltsDataAccessException {

                try {

                    String respEntity = oauthClient.post()

                            .uri(uriBuilder -> uriBuilder.queryParam("scope", oauthScope).queryParam("grant_type", grantType)
                                    .build())
                            .headers(headers -> headers.setBasicAuth(secretHeaderValue))

                            .retrieve()

                            .bodyToMono(String.class)

                            .block();

                    if (respEntity == null)
                        throw new UnableToGetOAuthTokenException(
                                "Exception while fetching OAUthToken as response from OAUth service is null resposne body");

                    try {
                        return mapper.readValue(respEntity, ObjectNode.class).get(oauthResponseTokenKeyName).asText();
                    } catch (JsonProcessingException e) {

                        logger.error("Exception while pasring token from Oauth ", e);
                        throw new UnableToGetOAuthTokenException(
                                "Exception while fetching OAUthToken as response from OAUth service is null resposne body");

                    }
                } catch (WebClientRequestException e) {
                    logger.error("Request Exception to OAUth: message {}", e.getMessage(), e);
                    logger.error("", e);
                    throw new VoltsDataAccessException(e.getMessage(), HttpStatus.REQUEST_TIMEOUT.value());
                }

                catch (WebClientResponseException e) {

                    
                    throw new VoltsDataAccessException(e.getMessage(), e.getRawStatusCode());
                }
            }

            @Retryable(value = VoltsDataAcessException.class)
            public ResponseEntity<VoltsResp> postSaveMeetingDetails(SaveVoltsReq voltsReq)
                    throws VoltsDataAcessException {

                try {

                    ResponseEntity<VoltsResp> resp = voltsDataAccessClient.post()
                            .uri(saveMeetingEndPoint, uri -> uri.queryParam("apikey", apiKey).build())
                            .headers(headers -> headers.setBearerAuth(postOAuthToken()))

                            .contentType(MediaType.APPLICATION_JSON).bodyValue(voltsReq).retrieve()

                            .toEntity(VoltsResp.class).block();

                    return resp;
                } catch (WebClientRequestException e) {
                    throw new VoltsDataAcessException(e.getMessage(), HttpStatus.REQUEST_TIMEOUT.value());
                } catch (WebClientResponseException e) {
                    throw new VoltsDataAcessException(e.getMessage(), e.getRawStatusCode());
                }

            }


        }

        
 

Мои тестовые занятия

WebClienrTests.java

             import static org.assertj.core.api.Assertions.assertThat;

        import org.junit.jupiter.api.AfterEach;
        import org.junit.jupiter.api.BeforeEach;
        import org.junit.jupiter.api.Test;
        import org.junit.runner.RunWith;
        import org.springframework.beans.factory.annotation.Autowired;
        import org.springframework.boot.test.context.SpringBootTest;
        import org.springframework.boot.test.mock.mockito.MockBean;
        import org.springframework.test.context.junit4.SpringRunner;
        import org.springframework.web.reactive.function.client.WebClient;

        import com.fasterxml.jackson.databind.ObjectMapper;
        import com.test.stats.volts.busops.config.WebClientConfig;
        import com.test.stats.volts.busops.utils.ServiceUtil;

        import okhttp3.mockwebserver.MockResponse;
        import okhttp3.mockwebserver.MockWebServer;

        @SpringBootTest(classes = { ServiceUtil.class, WebClientConfig.class,
                ObjectMapper.class })
        @RunWith(SpringRunner.class)
        class ServiceUtilTests {

            public static MockWebServer mockServer = new MockWebServer();

            @MockBean
            WebClientConfig webClientCondfig;

            @Autowired
            ServiceUtil serviceUtil;

            @MockBean(name = "oauthWebClient")
            WebClient oauthClient;

            @MockBean(name = "voltsDataAccessWebClient")
            WebClient voltsDataAccessWebClient;

            @BeforeEach
            void startMockServer() throws Exception {

                mockServer.start(9090);

                oauthClient = WebClient.create(mockServer.url("/").url().toString());
            }

            @AfterEach
            void stopMockServer() throws Exception {
                mockServer.shutdown();
            }

            @Test
            void testPostOAuth() throws Exception {
                mockServer.enqueue(new MockResponse().setResponseCode(200).setBody("OAuthToken"));
                String expected = serviceUtil.postOAuthToken();
                assertThat(expected).isNotNull().isEqualTo("OAuthToken");
            }

        }
 

Когда я запускаю вышеуказанный тест, я получаю эту ошибку

 java.lang.NullPointerException: 
 

postAuthToken() При установке заголовков .headers(headers -> headers.setBasicAuth(secretHeaderValue))

Пожалуйста, помогите, как высмеять все это

Комментарии:

1. Каковы ваши намерения в этом тесте? Напишите интеграционный тест для всего вашего приложения или протестируйте свой ServiceUtil отдельно? Пожалуйста, также добавьте весь раздел импорта для вашего теста. Похоже, вы смешиваете JUnit 4 и 5. Это может быть полезно для начала работы с модульным и интеграционным тестированием приложений Spring Boot .

2. @rieckpil Я отредактировал свой вопрос пожалуйста, проверьте сейчас, я на самом деле пытаюсь протестировать postoauthToken() метод ServiceUtil.java , который бросает меня NulPOinterException на настройку заголовков

3. затем, пожалуйста, также добавьте сюда весь исходный код ServiceUtil класса, чтобы понять его зависимости. Пожалуйста, также убедитесь, что ваш код правильно отформатирован.

4. Добавлено, пожалуйста, проверьте.

5. @rieckpil вам нужна дополнительная информация ?