联合测试

Federation 允许你扩展或者引用在一个 Graph 中已存在的类型。DGS 根据 DGS 拥有的 schema 完成部分查询,而 Gateway 负责从其他 DGS 获取数据。

不通过 Gateway 来测试联合查询

通过复制 Gateway 将发送给 DGS 的查询格式,可以独立测试 DGS 的联合查询。这并不涉及 Gateway,因此 DGS 不负责查询响应中将混合的部分。如果希望验证 DGS 能够返回适当的数据以响应联合查询,那么这种技术非常有用。

我们一起看一个例子,schema 扩展了已经在另一个 DGS 中定义的 Movie 类型。

type Movie @key(fields: "movieId")  @extends {
    movieId: Int @external
    script: MovieScript
}

type MovieScript  {
    title: String
    director: String
    actors: [Actor]
}

type Actor {
    name: String
    gender: String
    age: Int
}

现在你想要验证你的 DGS 能够通过根据 movieId 字段的混合了 script 字段来实现 Movie 查询。通常,Gateway 将会以以下格式发送一个 _entities 请求:

 query ($representations: [_Any!]!) {
        _entities(representations: $representations) {
            ... on Movie {
                movieId
                script { title }
        }}}

representations 输入是一个变量Map,这个 map 包含了设置了 Movie__typename 字段以及 movieId 为值。例如 12345

你现在可以通过手动创建 query 的方式设置一个 Query Executor 来测试,或者你也可以使用 client code generation 提供的Entities Query Builder API 来生成这个联合 query。

这里有一个使用手动创建 _entities query 的方式查询 Movie 的例子:

@Test
    void federatedMovieQuery() throws IOException {
         String query = "query ($representations: [_Any!]!) {" +
              "_entities(representations: $representations) {" +
                  "... on Movie {" +
                      "movieId " +
                      "script { title }" +
         "}}}";

        Map<String, Object> variables = new HashMap<>();
        Map<String,Object> representation = new HashMap<>();
        representation.put("__typename", "Movie");
        representation.put("movieId", 1);
        variables.put("representations", List.of(representation));

        DocumentContext context = queryExecutor.executeAndGetDocumentContext(query, variables);
        GraphQLResponse response = new GraphQLResponse(context.jsonString());
        Movie movie = response.extractValueAsObject("data._entities[0]", Movie.class);
        assertThat(movie.getScript().getTitle()).isEqualTo("Top Secret");
    }

Using the Entities Query Builder API

或者,您可以使用 EntitiesGraphQLQuery 来构建 graphql 请求,并结合 code generation 插件来生成使用请求构建器所需的类,从而生成联合查询。这提供了一种方便的类型安全的方法来构建查询。

要设置 code generation 以生成构建查询所需的类,请遵循这里的说明。

需要在 build.gradle 中添加 com.netflix.graphql.dgs:graphql-dgs-client:latest.release 依赖。

现在,我们可以编写一个使用 EntitiesGraphQLQueryGraphQLQueryRequestEntitiesProjectionRoot 来构建查询的测试。最后,还可以使用 GraphQLResponse 提取响应。

配置如下:

@Test
    void federatedMovieQueryAPI() throws IOException {
        // constructs the _entities query with variable $representations containing a 
        // movie representation that represents { __typename: "Movie"  movieId: 12345 }
        EntitiesGraphQLQuery entitiesQuery = new EntitiesGraphQLQuery.Builder()
                    .addRepresentationAsVariable(
                            MovieRepresentation.newBuilder().movieId(1122).build()
                    )
                    .build();
        // sets up the query and the field selection set using the EntitiesProjectionRoot
        GraphQLQueryRequest request = new GraphQLQueryRequest(
                    entitiesQuery,
                    new EntitiesProjectionRoot().onMovie().movieId().script().title());

        String query  = request.serialize();
        // pass in the constructed _entities query with the variable map containing representations
        DocumentContext context = queryExecutor.executeAndGetDocumentContext(query, entitiesQuery.getVariables());

        GraphQLResponse response = new GraphQLResponse(context.jsonString());
        Movie movie = response.extractValueAsObject("data._entities[0]", Movie.class);
        assertThat(movie.getScript().getTitle()).isEqualTo("Top Secret");
    }

最后更新于

这有帮助吗?