使用 quarkus-smallrye-graphql 进行单元测试

Unit Testing with quarkus-smallrye-graphql

在带有 quarkus-smallrye-graphql lib 的 quarkus 项目中,有没有办法像这样对 GraphQL 资源对象进行单元测试:

@GraphQLApi
public class ProductResource {

    @Inject
    private ProductRepository productRepository;

    @Query("products")
    @Description("Get all Products")
    @RolesAllowed({"USER","ADMIN"})
    public List<Product> findAll() {
        return this.productRepository.findAll().list();
    }

    @Mutation
    @Description("Create a new Product")
    @RolesAllowed("ADMIN")
    public Boolean createProduct(String name, Double price) {
        return this.productRepository.createProduct(name, price);
    }
}

我希望能够在单元测试中发送 GraphQL 查询(没有身份验证 inactivated/or)以验证我的注释,但我没有找到任何记录的方法来执行此操作。

如果您可以使用纯 HTTP 请求进行通信,那么这样的方法就可以了

@QuarkusTest
public class ProductRepositoryTest {

    @Test
    public void testQuery() {
        RestAssured.given()
                .when()
                .contentType("application/json")
                .body("{ \"query\": \"{" +
                        "  products {" +
                        "    name" +
                        "    price" +
                        "  }" +
                        "}\"" +
                        "}")
                .post("/graphql")
                .then()
                .statusCode(200)
                .body("data.products", Matchers.not(Matchers.emptyArray()));
    }
}

还可以选择使用来自 SmallRye GraphQL 的类型安全 GraphQL 客户端(请参阅我的存储库中的示例:https://github.com/jmartisk/mock-artifacts/tree/master/graphql/graphql-client)- 它应该可用于测试目的,即使它的级别非常高,所以您可能会丢失一些更细粒度的功能。 很快,也会有不同类型的客户端——动态客户端,但 SmallRye GraphQL 还不支持。

上次成功尝试:

  RestAssured.given()
                .when()
                .contentType("application/json")
                .body("{ \"query\": \"{" +
                        "  products {" +
                        "    name" +
                        "    price" +
                        "  }" +
                        "}\"" +
                        "}")
                .post("/graphql")
                .then().log().ifValidationFails()
                .statusCode(200)
                .body("data.products.name", Matchers.hasItems("Ten", "Twenty"))
                .body("data.products.price", Matchers.hasItems(Matchers.equalTo(10f), Matchers.equalTo(20f)));

注意:我已停用安全性以使单元测试正常工作。

https://claudioaltamura.de/api/graphql-apis-with-quarkus with source code at https://github.com/claudioaltamura/quarkus-graphql-superheroes. Based on that when using the official demo code at https://quarkus.io/guides/smallrye-graphql 中记录了一个很好的示例,我们可以编写此测试:


import io.quarkus.test.junit.QuarkusTest;
import io.restassured.RestAssured;
import io.restassured.http.ContentType;
import io.restassured.response.Response;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.apache.commons.text.StringEscapeUtils;
import org.junit.jupiter.api.Test;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.stream.Collectors;
import static org.assertj.core.api.Assertions.assertThat;

class GqlTestHelpers {

    @SneakyThrows
    public static String loadQueryAsJson(String resource) {
        Path path = Paths.get(resource);
        String allLines = Files.readAllLines(path).stream().collect(Collectors.joining("\n"));
        val quotedQuery = StringEscapeUtils.escapeJson(allLines);
        val json = "{ \"query\": \"" + quotedQuery + "\"}";
        return json;
    }
}

@QuarkusTest
@Slf4j
public class FilmResourceTest {

    @Test
    public void testQuery() {

        val query = GqlTestHelpers.loadQueryAsJson("src/test/resources/allFilms.gql");

        final Response response = RestAssured.given()
                .contentType(ContentType.JSON)
                .body(query)
                .when()
                .post("/graphql")
                .then()
                .assertThat()
                .statusCode(200)
                .and()
                .extract()
                .response();

        log.info(response.body().prettyPrint());

        final List<Film> films = response.jsonPath().getList("data.allFilms", Film.class);
        log.info(films.toString());

        assertThat(films)
                .isNotEmpty()
                .hasSize(3)
                .extracting(Film::getTitle)
                .contains("A New Hope", "The Empire Strikes Back", "Return Of The Jedi");
    }
}

最后很厉害的assert语句是基于

    <dependency>
      <groupId>org.assertj</groupId>
      <artifactId>assertj-core</artifactId>
      <version>3.20.2</version>
      <scope>test</scope>