Testing GraphQL with Specifications: A Deep Dive with Reqnroll

Documents and tools for searching

GraphQL has been around since 2012, yet many developers haven’t had the chance to work with it. Personally, I’ve been using GraphQL on and off for several years, both in personal and professional projects. Recently, I’ve been diving deeper into it again—and I’ve fallen in love with it all over.

While implementing a few queries and mutations, I started to wonder: how could I effectively test my GraphQL implementation? Specifically, how could I send queries and mutations with a GraphQL client directly from my tests to ensure everything works as expected?

After some experimentation, I found a solution I’m excited to share: combining specifications with Reqnroll , the .NET WebApplicationFactory , and the Strawberry Shake GraphQL client to test a Hot Chocolate GraphQL server . This approach not only works seamlessly but also results in clean, readable specifications.

In this article, I’ll guide you through the process of setting up these tests, allowing you to test your own GraphQL server with clarity and confidence. Let’s get started!

GraphQL, a very short introduction

This article is not intended to explain what GraphQL is, but here’s a very short introduction: GraphQL is a query language and a runtime that lets clients fetch exactly the data they need, making it incredibly flexible and efficient. It supports queries, mutations, and subscriptions—where queries and mutations can roughly be compared to GET and POST methods in REST.

One of the big differences between GraphQL and REST is that with GraphQL, you can specify exactly what data you need. This eliminates the problem of under-fetching (not enough data) or over-fetching (too much unnecessary data), making GraphQL an excellent choice for optimizing data transfer.

An example query in the GraphQL query language, with the result in JSON.

An example query in the GraphQL query language, with the result in JSON.

Figure 1: “An example query in the GraphQL query language, with the result in JSON.”

This query requests a list of books, and from each book the fields title, auhor and the ISBN number.

Why testing GraphQL, and why with specifications

GraphQL is often used as a proxy to deliver data rather than a repository of complex business logic. This makes traditional unit tests less effective for testing GraphQL APIs. Instead, the focus shifts to higher-level concerns, such as:

  • Is authentication and authorization configured correctly?
  • Do resolvers work as expected and deliver the correct information?
  • Are all data flows implemented as required?

Testing the GraphQL server ensures that these critical aspects of the API are functioning properly. Unlike REST APIs, GraphQL relies on resolvers that dynamically assemble and deliver the requested data. As a result, many test scenarios for a GraphQL API are broader in scope than typical unit tests.

This is where specification-driven testing fits perfectly. Inspired by Behavior-Driven Development (BDD) and Specification by Example (SbE), this approach emphasizes defining tests as structured examples that represent real-world use cases. By focusing on what the API should do rather than how it does it, specification-driven testing ensures all parts—authentication, authorization, resolvers, and data flows—are verified.

The above specification illustrates the use case depicted in the GraphQL query shown in figure 1. It represents a request for a list of books, retrieving specific fields such as the title, author, and ISBN number for each book.

Overview of tools and techniques

For this post I created an example project , and I used the following tools:

Example Application: A Simple Bookstore API

To demonstrate the testing approach, I’ll use a straightforward example : a GraphQL API server for a bookstore. This application includes:

  • A list of books, each with details such as title, author, and publication year.
  • Authorization and authentication mechanisms to control access to certain actions.
  • The ability to add new books, but only if the user is logged in as a store owner.

This simple setup is perfect for showcasing how to test key aspects of a GraphQL API, including query responses, mutation behaviors, and authentication rules. Throughout the article, I’ll use this bookstore API as my testing target to walk through examples of specification-driven tests.

Writing the first specification

Specifications are written in a language called Gherkin , a business-readable, domain-secific language (DSL). Gherkin bridges the gap between technical and non-technical stakeholders by allowing specifications to be written in a human-readable format, while still enabling them to be bound to machine-executable code.

Here is our first specification, for a customer that wants to see a list of available books:

The specifications are bound to code to make the scenarios testable. While diving into how this binding works is beyond the scope of this article, here’s a screenshot of how the specifications are connected to the underlying code:

Test results in JetBrains Rider

Figure 2: “Test results in JetBrains Rider”

Executing GraphQL queries in tests

To execute GraphQL queries in the test project, a few steps are required. First, you need to create a query in the GraphQL directory, which is automatically created when installing the Strawberry Shake client.

For the specification above, the query is stored in the file BookQueries.graphql , and it looks like this:

After saving the GraphQL file and building the test project, the Strawberry Shake client generates the code for a new client, after which the query can be executed. In this project, the code to execute the query looks like this:

The final step is to run the query against the GraphQL server. To do this in a test environment, I’ll use the .NET in-memory TestServer option. This approach allows the query to be executed as if it were hitting a real server, without the need for external infrastructure.

To achieve this, I need to create a custom WebApplicationFactory. This factory sets up and configures the application for testing, ensuring it matches the production setup as closely as possible while allowing for test-specific configurations.

Here’s a basic outline of the custom WebApplicationFactory:

For more details on how to configure and use a custom WebApplicationFactory, you can refer to the documentation on integration tests. In the sample application I override a `StockService` to demonstrate how to test a GraphQL resolver too.

After implementing the setup for testing, the project is ready to be extended with additional specifications. These specifications allow you to cover a wide range of scenarios, from complex queries to edge cases involving authentication and authorization.

Below is the output of all the tests in the example project:

Test results in JetBrains Rider

Figure 3: “Test results in JetBrains Rider”

This output shows that all the implemented specifications have been successfully tested against the GraphQL server. By extending the project with more specifications, you can ensure that every aspect of your API behaves as expected under real-world conditions.

With this foundation in place, you can confidently expand your test suite to handle additional queries, mutations, and edge cases as your GraphQL API evolves.

Conclusion

Testing a GraphQL API can be challenging due to its flexibility and dynamic nature. However, with the right tools and approach, it’s not only achievable but can also be done in a clean and readable way.

A word of caution: specifications are meant to be written in a functional way. As your documents grow and become more complex, it can be tempting to specify complete queries or results directly in the specifications. This often leads to specifications that are large, unreadable, and difficult to maintain—a trap that’s always lurking when writing specifications, not just for GraphQL.

Whether you’re starting with a simple bookstore API or tackling a more complex system, the techniques discussed in this article can be adapted and scaled to suit your needs. The combination of a structured specification language like Gherkin and the powerful tools provided by the .NET ecosystem ensures your tests remain readable, maintainable, and effective.

I hope this article inspires you to explore specification-driven testing in your GraphQL projects. If you’re interested in learning more about integration testing with WebApplicationFactory or diving into advanced use cases, check out the resources linked below.

Happy testing!