logo logo

Testing GraphQL API

main post image

In the previous chapter, we reviewed some of the basics of GraphQL, differences between REST and GraphQL and core concepts of GraphQL. Now let’s understand more about some of the internal working of core-concepts. And, What components suggested for testing GraphQL?

Table of Contents: The Definitive Guide to Testing GraphQL API

  1. Introduction and getting started with GraphQL
  2. You’re here → Testing GraphQL APIs
  3. Cross-functional testing of GraphQL APIs – Coming Soon

GraphQL Test Playground

We will be working with a simple Movie and Actor based GraphQL API that shows some name of the movie and list of movies and actor details. I’ve developed and Open-Sourced here. Firstly, let us look at the Schema of the API that we are going to use for testing. And we will be using the same for the upcoming chapters in this course.

I’ve used code sandbox to deploy the source code of GraphQL server component and it is accessible here. This will be available for access for a limited time, and when you are reading this and the sandbox environment is not accessible, I will request you to clone the source code and build it locally.

To recap, we’ve learned from our previous chapter that, everything is perceived as a graph and it’s connected (think of the GraphQL Logo) and represented as a single endpoint. In REST, we can see multiple endpoints for different functions of your product. In GraphQL, it’s through a single endpoint, and the main entry point is via RootQueryType as the name suggests, it’s the root and a single entry point towards accessing your server component. The below picture depicts precisely that, and we have four types movie, actor, movies and actors that users can query for data. And we’ve also seen different scenarios that users may query in the previous chapter.

graphql schema viewer

Querying GraphQL API

Before we jump onto testing components of GraphQL, firstly we need to understand how to call a GraphQL API over HTTP. There are different ways in which you could trigger an API. I’ve shared below some easy and commonly used ways as below:

    • cURL: Curl is a popular command-line tool and library for processing data over HTTP (and many other) protocols. You will have to send a curl command along with three parameters.
          1. Firstly, the content-type application/json because the query is part of JSON.
          2. Secondly, the data sent will be actual query like { "query": "{ movies { name } }" }
          3. Finally, the GraphQL endpoint: https://n7b67.sse.codesandbox.io/graphql?And mostly all the GraphQL calls would be based on HTTP verb POST.
          4. In summary, below is the curl command to query your GraphQL endpoint.
curl -X POST -H "Content-Type: application/json" --data '{ "query": "{ movies { name, genre } }" }' https://n7b67.sse.codesandbox.io/graphql | jq .

Querying GraphQL API

  • GraphiQL: It’s a React-based Front-end that provides a nice GUI for us to compose queries from the browser. Users have an option to set a boolean flag to set graphiql to be True in your app.jsfile. Then, GraphiQL is accessible automatically the moment you build the server component via nodemon or node.

A GIF image showing a demo of GraphiQL window

  • Using fetch library: The code below is written based on JavaScript. But you can do this in any language. It is basically an extension of the cURL command that we saw above.
    require('isomorphic-fetch');
    
    fetch('https://n7b67.sse.codesandbox.io/graphql', {
    
      method: 'POST',
    
      headers: { 'Content-Type': 'application/json' },
    
      body: JSON.stringify({ query: '{ movies { name, genre } }' }),
    })
      .then(response => response.json())
    
      .then(response => console.log(response.data));

Testing GraphQL

There are several ways your application could break, and testing is very much an essential activity to release code with confidence. Speaking of testing GraphQL API’s, there are multiple ways and methodologies that you could perform. Firstly, let us take a look at the components to check in GraphQL and then we will look at implementing a testing methodology.

We all know the famous Test Pyramid by Mike Cohn. It’s a great visual metaphor telling about the tests you could write at different levels. We all know it is proven to be effective in many ways for different environments and scenarios.

There is also a new way of looking at the organizing of your tests called the Testing Trophy 🏆 that helps write tests at different granular levels. I like both the testing metaphors, and it’s best to apply whatever works per the environment and the scenario. Testing GraphQL APIs can utilize the Testing Trophy very well because the lower level of the testing trophy recommends checking for static checks. We have a Schema defined with its strong types and stands as a source of truth to other field type and parameters, you can easily do a lot of static checks. Let’s look at some of the core components in GraphQL that should be tested which will fit into different levels like the Unit, Integration and Static checks.

Components to test in GraphQL

Testing Schema:

The first choice to go about testing GraphQL APIs would be to look at Schema and check for those types that you’d have had defined. Here is a cool handy cheat-sheet for reference to write schema succinctly, useful for developers and testers. Schema can be tested by the following ways:

  • Static Type Checks: A lot of these can be tested using two of my favourite tools, the graphql-schema-linter and eslint-plugin-graphql and of course you could use Flow to perform static checks.
  • Mock Schema & Test queries: You should consider mocking the schema using mock-server that should be available in both graphql-tools or apollo-servertools and write tests(queries) with all possible combinations.
import { makeExecutableSchema } from '@graphql-tools/schema';
import { addMocksToSchema } from '@graphql-tools/mock';
import { graphql } from 'graphql';

const schemaString = `type Query {
      movie(id: ID): Movie
      actor(id: ID): Actor
   }

   type Actor {
      id:String!
      name:String!
      age:Int
      movies:Movie
   }

   type Movie {
      id:String
      name:String!
      genre:String
      actor:Actor
   }

   type Movies {
      movies:[Movie]
   }

   type Actors {
      actor:[Actors]
   }`;

// Make a GraphQL schema with no resolvers
const schema = makeExecutableSchema({ typeDefs: schemaString });

// Create a new schema with mocks
const schemaWithMocks = addMocksToSchema({ schema });

const query = `
query getmoviewithid {
  movie(id: 6) { name, genre }
}
`;

graphql(schemaWithMocks, query).then((result) => console.log('Got result', result));

Testing Query:

Testing queries are easy with GraphiQL if you are using JavaScript to build GraphQL server components. There are also other plugins to like Altair that can be used to test if you are using other language clients to build GraphQL server. The above GIF under GraphiQL section exactly shows the same.

  • You can also test the queries in an automated fashion using libraries like request and supertest
const supertest = require("supertest");
const expect = require("chai").expect;
const schema = require("../schema/schema");

let baseURL = supertest("http://localhost:4000/graphql");
let list_users = `{
    movie(id:"1234595830") {
      name
      id
      actor {
        name
        age
        id
      }
    }
  }
  `;
describe("POST Request", async () => {
  let post_resp;
  it("makes a POST call ", async () => {
    post_resp = await baseURL
      .post(list_users);
    await console.log(post_resp.body);
//Do any other validation here.
  });
});
  • Using easygraphql-tester you could test for different queries against the schema definition.
    const EasyGraphQLTester = require('easygraphql-tester')
    const fs = require('fs')
    const path = require('path')
    
    const schemaCode = fs.readFileSync(
      path.join("./schema/movies-schema.gql"),
      "utf8"
    );
    const tester = new EasyGraphQLTester(schemaCode)
    describe("Test Schema, Queries and Mutation", () => {
      let tester;
    
      before(() => {
        tester = new EasyGraphQLTester(schemaCode);
        //just to make sure schema comes through swiftly
        //console.log(util.inspect(tester))
      });
    
    it("Should pass with a valid query", () => {
          
          const query = `
          {
            movies {
              name
              genre
              actor{
                name
                age
              }
            }
          }      
          `;
          // First arg: true because the query is valid
          // Second arg: query to test
          tester.test(true, query);
        });
    });

Testing Mutations:

Mutations modify data in our database and return us a value. We’ve learned from the previous chapter that Mutations are equivalent to CRUD operations in the REST API world. Testing Mutations are very important as it involves testing data access and addition to databases. Mutations can be tested by the following ways:

  • Using GraphiQL: Use the below mutation query in the GraphiQL client and test for valid response and message.
    mutation{ addMovie(name: "MovieName", genre: "Action", actorId:"The ID of Actor"){ name genre } }
  • Using easygraphql-tester
    it("Should fail with a Invalid mutation query", () => {
         const mutation = `
         mutation addMovie($id: String!, $name: String!, $genre: String) {
           addMovie(id: $id, name: $name, genre: $genre) {
               id
               name
               genre
           }
         }      
         `;
         // First arg: false because the query is Invalid
         // Second arg: query to test
         tester.test(true, mutation, {
           id: "id123",
           name: "testMovie",
           genre: "Action",
         });
       });

Testing Resolvers:

Resolvers are query handlers and are pure JavaScript functions. The Resolver function would typically have the following syntax:

fieldName(obj, args, context, info) { result }

Let’s take our example query to get movies as below and see how Resolver functions would be like:

query {
  movies{
    name
    genre
    actor{
      name
    }
  }
}
  1. obj in Query.movies will be whatever the server configuration passed for rootValue.
  2. obj in Movie.name and Movie.genre will be the result from movies, usually, a movies object from the backend.
  3. obj in Actor.name and will be one item from the actor result array.

GraphQL query is a series of function calls (resolver functions) nested in a way according to the query pattern. So testing Resolvers would be the same as unit testing a function in JavaScript.

I hope that by now, you are aware of the core component of GraphQL and how to test those components. Now let’s go ahead and look at how to test GraphQL APIs using some of the tools and libraries in the API testing ecosystem.

Testing GraphQL using Tools in the API Ecosystem

Testing GraphQL with Postman

Exploratory testing with GraphQL is quite simple, Postman has inbuilt support to run GraphQL queries. Let’s see how can you do that:

  • Step 1: Select the Schema type as GraphQL under New API dialog. Upload your GraphQL Schema onto your Postman, this will help us assist writing easy queries and also help us with supporting query completion. This is optional, and you could even test it without uploading Schema.

Testing GraphQL with Postman

  • Step 2: Next up, you can start creating a collection and add an API call onto your collection. In this case, I’ve named our collection as TestProject-GraphQL and have three POST calls, as shown on the left-hand side in the below picture. I also have three different POST calls testing for different data.
    Testing GraphQL with Postman
  • Step 3: Next, the API test is just to demonstrate the usage of Query variable, say when you’d want to query for a particular Movie or Actor using its unique identifier.
    query($id: ID!){
      actor(id:$id){
          name
          age
          movies{
              name
          }
      }
    }

Testing GraphQL with Postman

  • Step 4: We can make use of tests tab in Postman to automate and validate the response.
    pm.test("Status code is 200", function () {
        pm.response.to.have.status(200);
    });
    
    pm.test("Verify Movie Name", function () {
        var responsePayload = pm.response.json();
       pm.expect(responsePayload.data.movies).to.be.oneOf(["The Matrix","Inception","Inferno"]);
    
    });
    
  • Step 5: We can automate these tests using Tests section and use Postman Runner to execute your GraphQL API tests via command line too.
    Testing GraphQL with Postman 🔱 Myth: GraphQL always returns 200 as status code. 

    It’s advisable not to check for status code, as you see on the above screenshot the Get List Of All Movies test has failed but still shows 200 as status code. GraphQL allows you to configure custom error codes, so the best practice would be to set custom error code for particular error and then assert.

Testing GraphQL using Rest Assured

Rest Assured allows us to test REST APIs easily and is well known in the Java world for automating REST APIs. Good news (!) is that you could still use Rest Assured to test for GraphQL APIs with one condition though! The GraphQL query(request) in itself is not a JSON payload and here is how you could achieve:

  • Firstly, convert the GraphQL query into Stringified JSON format.
  • Secondly, pass the converted String as Body parameters to the Request.
  • Then finally, validate the response.
@BeforeClass
    public static void createRequestSpecification() {

        requestSpecification = new RequestSpecBuilder().
                setBaseUri("http://localhost").
                setPort(4040).
                build();
    }

    @Test
    public void SimpleTest() {
        given()
                .spec(requestSpecification)
                .accept(ContentType.JSON)
                .contentType(ContentType.JSON)
                .body("{\"query\":\"query {\\n  movies{\\n    name\\n  }\\n}\",\"variables\":{}}" )
                .post("/graphql")
                .then()
                .statusCode(200).log().all();

    }

💸 Tip: The Generate Code Snippets option in Postman will help you get the Stringified JSON.

Testing GraphQL using Rest Sharp

[SetUp]
       public void Setup()
       {
           _restClient = new RestClient("http://localhost:4040");

       }
       [Test]
       public void TestGraphQL()
       {
           //Arrange
           _restRequest = new RestRequest("/graphql" , Method.POST);
           _restRequest.AddHeader("Content-Type", "application/json");
           _restRequest.AddParameter("application/json", 
               "{\"query\":\"{\\n  movie(id:\\\"5ec2caaaa0f98451a25d1429\\\") " +
               "{\\n    name\\n    id\\n    actor {\\n      name\\n      age\\n      id\\n    }\\n  }\\n}\\n\"," +
               "\"variables\":{}}",
               ParameterType.RequestBody);
           //Act
           _restResponse  = _restClient.Execute(_restRequest);

           //Assert
           //do validation
           Console.WriteLine("Printing results for fun : "+_restResponse.Content);

           }

Testing GraphQL using Karate

The Karate framework has built-in support for testing GraphQL API and it’s seamless. Unlike the other options that we saw above. If you are using Karate for API testing then, it’s very straight forward to test, you can pass the GraphQL Query as it is and validate the response using Karate’s match assertions.

Scenario: GraphQL request to get all data fields
    # note the use of text instead of def since this is NOT json
    Given text query =
    """
    {
  movies{
    name
    genre
    actor{
      name
      age
      id
    }
  }
}
    """
    And request { query: '#(query)' }

    When method POST
    # pretty print the response
    * print 'response:', response

    # json-path makes it easy to focus only on the parts you are interested in
    # which is especially useful for graph-ql as responses tend to be heavily nested
    # '$' happens to be a JsonPath-friendly short-cut for the 'response' variable
    #* match $.data.movie.name == 'The Matrix'
    # the '..' wildcard is useful for traversing deeply nested parts of the json
    * def actor0 = get[0] response..actor
    * match actor0 contains { name: 'Keanu Reeves', id: '5ec2ac72abe66a4b8a184f96', age: 56 }

    * def actor2 = get[2] response..actor
    * match actor2 contains { name: 'Tom Hanks', id: '5ec2abab84395b4b4c71ed9d', age: 63 }

Testing GraphQL using TestProject

TestProject is a cloud-hosted, 100% free test automation platform built on Selenium and Appium for all testers and developers. It has also got Add-ons that users can use to do additional testing on the same cloud. Here, we can use the community Add-on called RESTful API Client and invoke a POST call to query a GraphQL API. Please follow the steps as mentioned in this blog post.
This is how your test would be, a very simple test to hit the endpoint using POST call and pass the Stringified JSON payload into the Body and you are done.

TestProject API Testing

Once you execute the tests, the tests are executed in seconds and you could verify it from the Reports sections as well. A sample response as below:

Sample Response from REST API Testing with TestProject

Testing GraphQL using Test GraphQL Java

If you are not using any of the above BDD frameworks for API testing and looking for a standard Java project to test GraphQL APIs. Test-GraphQL-Java project by Vimal Selvam should be easy to implement. Simply add the below maven dependency to your Java project and you are done.

<dependency>
    <groupId>com.vimalselvam</groupId>
    <artifactId>test-graphql-java</artifactId>
    <version>1.0.0</version>
</dependency>

package test.graphql;
import java.io.*;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

import com.vimalselvam.graphql.GraphqlTemplate;
import org.testng.Assert;
import org.testng.annotations.Test;

import okhttp3.*;

/**
 * Test
 */
public class TestGraphQL {

    private static final OkHttpClient client = new OkHttpClient();
    private final String graphqlUri = "https://n7b67.sse.codesandbox.io/graphql";

    private Response prepareResponse(String graphqlPayload) throws IOException {
        RequestBody body = RequestBody.create(MediaType.get("application/json; charset=utf-8"), graphqlPayload);
        Request request = new Request.Builder().url(graphqlUri).post(body).build();
        return client.newCall(request).execute();
    }

    @Test
    public void testGraphqlWithInputStream() throws IOException {

        // Read a graphql file as an input stream
        InputStream iStream = TestGraphQL.class.getResourceAsStream("/movies.graphql");

        // Create a variables to pass to the graphql query
        ObjectNode variables = new ObjectMapper().createObjectNode();
        variables.put("id", "5ec2caaaa0f98451a25d1429");

        // Now parse the graphql file to a request payload string
        String graphqlPayload = GraphqlTemplate.parseGraphql(iStream, variables);

        // Build and trigger the request
        Response response = prepareResponse(graphqlPayload);

        Assert.assertEquals(response.code(), 200, "Response Code Assertion");

        String jsonData = response.body().string();
        JsonNode jsonNode = new ObjectMapper().readTree(jsonData);
        System.out.println(jsonData);
        Assert.assertEquals(jsonNode.get("data").get("movie").get("name").asText(), "The Matrix");
    }
}

 

Outro!

Congratulations! 🎉 You’ve made it up until here. To summarize, by now, you are aware of core-components of GraphQL and how to test the different components and some tips and myths to keep in mind when testing GraphQL APIs. We also saw usage of popular tools like TestProject, Rest Assured, Rest Sharp and Karate.

We’ve looked at how GraphQL is different from REST and overcomes the problem of data fetching. However, GraphQL APIs will lead to n+1 problems due to multiple iterations that it may have to route through multiple databases. There are solutions like using Data Loader that would solve the problem. The Cross-functional requirements like the responsiveness, stability and some tracing mechanism for the APIs would really help build and streamline in a better way.

In the next and final chapter of this tutorial series, we will deep-dive and look at how to test for performance and responsiveness of the GraphQL APIs, and how to do the same using Open-Source libraries. Stay Tuned! 😉

Avatar

About the author

Manoj Kumar

Manoj Kumar is a Principal Consultant at ThoughtWorks. Manoj is an avid open-source enthusiast and a committer to Selenium & Appium project. And a member of the project leadership committee for Selenium. Manoj has also contributed to various libraries and frameworks in the automated testing ecosystem like ngWebDriver, Protractor and Serenity to name a few. An avid accessibility practitioner who loves to share knowledge and is a voluntary member of the W3C ACT-R group. In his free time, he contributes to Open-Source projects or research on Accessibility and enjoys spending time with his family. He blogs at AssertSelenium.

Join TestProject Community

Get full access to the world's first cloud-based, open source friendly testing community. Enjoy TestProject's end-to-end test automation Platform, Forum, Blog and Docs - All for FREE.

Join Us Now  

Comments

21 1 comment
  • Avatar
    Shraddha July 6, 2020, 12:26 pm

    Hi Manoj, First of all a very nice and comprehensive article. I am QA Automation Engg, I have been working on graphql with RestSharp, actually I am facing difficulties in performing request with body with variables, In this article you have mention variables in payload but Could you please gimme more insights on it.

Leave a Reply

popup image

Complete E2E Automation Solution!

Join over 10K organizations (from Wix, IBM, Payoneer and many more!) using the world's first FREE cloud-based test automation platform, supported by the #1 testing community.
Sign Up Now right arrow
FacebookLinkedInTwitterEmail