Как протестировать клиентский интерфейс Quarkus REST?

Я использую REST-клиент MicroProfile в Quarkus и хотел бы знать, как можно выполнить модульное тестирование пользовательских клиентских интерфейсов?

Пример услуги:

@Path("/v1")
@RegisterRestClient
public interface CustomService {

    @POST
    @Path("/custom")
    void postCustomObject(CustomObject object);
}

Можно ли написать модульный тест, охватывающий эту функциональность? Например, я хотел бы проверить, правильно ли обрабатывается тело запроса и содержит правильный JSON (тем более, что у меня есть проблема, когда поведение отличается между JVM и собственным режимом изображения).

Ресурсы сервера REST можно легко протестировать с помощью REST-гарантированного, но я не нашел ничего похожего для клиентских интерфейсов REST.

Руководство Quarkus по использованию клиента REST мне больше не помогает, так как для звонка используется реальный сервис. В моем случае серверная часть недоступна в процессе сборки / тестирования.

Какие-либо предложения?

1 ответ

Немного поздно, но я пытаюсь ответить на этот вопрос для справок в будущем. Хотя я согласен с комментарием @Héctor, может быть полезно протестировать сам клиент отдыха MicroProfile (например, для фактического тестирования обработчика ошибок) или в bean-компоненте, в который вводится остальной клиент.

В любом случае вам нужен фиктивный сервер, такой как WireMock. Официальное руководство по Quarkus действительно затрагивает эту тему . Я могу привести здесь пример (который я взял отсюда ).

Добавьте эту зависимость в свой pom.xml (если вы используете Maven):

      <dependency>
    <groupId>com.github.tomakehurst</groupId>
    <artifactId>wiremock-jre8</artifactId>
    <scope>test</scope>
    <version>${wiremock.version}</version> 
</dependency>

Создайте класс, который запустит фиктивный сервер перед выполнением тестов (и который отключит его, когда все они будут выполнены):

      package org.acme.getting.started.country;

import java.util.Collections;
import java.util.Map;

import com.github.tomakehurst.wiremock.WireMockServer;
import io.quarkus.test.common.QuarkusTestResourceLifecycleManager;

import static com.github.tomakehurst.wiremock.client.WireMock.*;

public class WiremockCountries implements QuarkusTestResourceLifecycleManager {

    private WireMockServer wireMockServer;

    @Override
    public Map<String, String> start() {

        wireMockServer = new WireMockServer();
        wireMockServer.start();

        //define a static response when the request matches a url declared as a regex 
        stubFor(get(urlEqualTo("/v2/name/GR"))
                .willReturn(aResponse()
                        .withHeader("Content-Type", "application/json")
                        //read the WireMock docs: you can even use a json file in /resources/__files/ (default expected location) in place of a string
                        .withBody(
                        """
                        [
                            {
                                "name": "Ελλάδα",
                                "capital": "Αθήνα"
                            }
                        ]
                        """
                        )));
        //remap the base url of the external service to the base url of the mock server 
        return Collections.singletonMap("org.acme.getting.started.country.CountriesService/mp-rest/url", wireMockServer.baseUrl());
    }

    @Override
    public void stop() {
        if (null != wireMockServer) {
            wireMockServer.stop();
        }
    }
}

Напоминание: на данный момент вы не можете протестировать bean-компонент @Singleton, поэтому поместите в остальной клиентский интерфейс аннотацию @ApplicationScoped.

Наконец, используйте этот класс в реальном тестовом классе:

      package org.acme.getting.started.country;

import javax.inject.Inject;

import io.quarkus.test.common.QuarkusTestResource;
import io.quarkus.test.junit.QuarkusTest;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import org.junit.jupiter.api.Test;

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

@QuarkusTest
@QuarkusTestResource(WiremockCountries.class)
class RegularCountriesServiceTest {

    @Inject
    @RestClient
    CountriesService countriesService;

    @Test
    void testGR() {
//      assertThat(countriesService.getByName("GR")).hasSize(10).extracting("name").contains("Greece");
        assertThat(countriesService.getByName("GR")).hasSize(1).extracting("name").contains("Ελλάδα");
    }
}

Если вы хотите протестировать остальной клиент на один уровень выше, все, что вам нужно сделать, это повторно использовать класс-оболочку для фиктивного сервера и ввести с помощью @Inject bean-компонент, который объявляет остального клиента как свою зависимость. Сделайте что-нибудь вроде этого:

      @QuarkusTest
@QuarkusTestResource(WiremockWrapperAsBefore.class)
class MyBusinessClassTest {

    @Inject
    MyBusinessClass myBusinessClass;

    @Test
    void testMyRestCleintInjectedIntoMyBusinessClass() {

        ResponseDTO dto = myBusinessClass.methodWhichCallsMyMicroProfileRestClient(String someParam);
        assertNotNull(dto);
    }
}

В противном случае было бы полезно в других сценариях создать реализацию прокси с RestClientBuilder для интерфейса клиента отдыха MicroProfile, как показано здесь :

      import java.net.MalformedURLException;
import java.net.URI;
import org.eclipse.microprofile.rest.client.RestClientBuilder;
import static org.junit.Assert.assertNotNull;
import org.junit.Test;


public class RestClientTest {

    @Test
    public void init() throws MalformedURLException {
        URI baseURI = URI.create("http://localhost:8080");
        PingClient client = RestClientBuilder.newBuilder().
                baseUri(baseURI).
                build(PingClient.class);                
        assertNotNull(client);
        String result = client.ping();
        assertNotNull(result);
    }
}

Соответствующий интерфейс угадать несложно, но он выглядит следующим образом:

      import javax.ws.rs.GET;
import javax.ws.rs.Path;
import org.eclipse.microprofile.rest.client.inject.RegisterRestClient;
        
@Path("/restclient/resources/ping")
@RegisterRestClient
public interface PingClient {

    @GET
    String ping();
}

В этом случае, если вы используете Quarkus, вам не понадобятся следующие зависимости, но я все равно сообщу об этом по ссылке выше, если кто-то использует MicroProfile, но не Quarkus:

      <dependencies>
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>javax</groupId>
        <artifactId>javaee-api</artifactId>
        <version>8.0</version>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.cxf</groupId>
        <artifactId>cxf-rt-rs-mp-client</artifactId>
        <version>3.3.1</version>
        <scope>test</scope>
    </dependency>
</dependencies>  
Другие вопросы по тегам