Testing GraphQL APIs — Queries, Mutations & Schema Testing Guide
In this tutorial, you'll learn about Testing Graphql APIs. We cover key concepts, practical examples, and best practices.
GraphQL API testing differs from REST testing because you have a single endpoint, flexible queries, and strongly typed schemas that define exactly what data clients can request. In this guide, you will learn how to test GraphQL queries and mutations, validate schema structure and resolver behavior, use snapshot testing for complex nested responses, and automate your GraphQL test suite in CI/CD. The DodaBrowser API team runs over 500 GraphQL tests against every schema change, ensuring the search and recommendation queries never break.
Learning Path
flowchart LR A[REST API Testing] --> B[GraphQL Basics] B --> C[Testing GraphQL APIs
You are here] C --> D[Schema Validation] D --> E[Performance Testing] style C fill:#f90,color:#fff
Testing GraphQL Queries
Test that queries return the expected shape and data:
import requests, json
GRAPHQL_URL = "http://localhost:4000/graphql"
def run_query(query, variables=None):
payload = {"query": query}
if variables:
payload["variables"] = variables
r = requests.post(GRAPHQL_URL, json=payload)
return r.json()
def test_get_user():
query = """
query GetUser($id: ID!) {
user(id: $id) {
id
name
email
}
}
"""
result = run_query(query, {"id": "1"})
assert "errors" not in result, f"Errors: {result.get('errors')}"
user = result["data"]["user"]
assert user["id"] == "1"
assert "name" in user
assert "email" in user
print("GetUser query test passed")
test_get_user()
Expected output:
GetUser query test passed
Testing GraphQL Mutations
Mutations change data and should be tested for success and error states:
def test_create_user():
mutation = """
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
email
}
}
"""
result = run_query(mutation, {
"input": {"name": "Alice", "email": "alice@test.com"}
})
assert "errors" not in result, f"Errors: {result.get('errors')}"
user = result["data"]["createUser"]
assert user["name"] == "Alice"
assert user["email"] == "alice@test.com"
print("CreateUser mutation test passed")
def test_create_user_validation():
mutation = """
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) { id name email }
}
"""
result = run_query(mutation, {
"input": {"name": "", "email": "invalid"}
})
assert "errors" in result
errors = [e["message"] for e in result["errors"]]
assert any("email" in e.lower() for e in errors)
print("CreateUser validation test passed")
test_create_user()
test_create_user_validation()
Expected output:
CreateUser mutation test passed
CreateUser validation test passed
Schema Validation Testing
Ensure your GraphQL schema defines the correct types, fields, and relationships:
import requests
def get_schema():
query = """
query IntrospectionQuery {
__schema {
types {
name
kind
fields {
name
type {
name
kind
}
}
}
}
}
"""
result = run_query(query)
return result["data"]["__schema"]
def test_schema_has_type():
schema = get_schema()
type_names = [t["name"] for t in schema["types"]]
required = ["User", "Query", "Mutation", "CreateUserInput"]
for name in required:
assert name in type_names, f"Missing type: {name}"
print("Schema type check passed")
def test_user_type_fields():
schema = get_schema()
user_type = next(t for t in schema["types"] if t["name"] == "User")
field_names = [f["name"] for f in user_type["fields"]]
expected = ["id", "name", "email", "createdAt"]
for field in expected:
assert field in field_names, f"Missing field: {field}"
print("User type field check passed")
test_schema_has_type()
test_user_type_fields()
Snapshot Testing GraphQL Responses
import json
def test_user_query_snapshot():
query = "{ user(id: 1) { id name email createdAt } }"
result = run_query(query)
snapshot = {
"data": {
"user": {
"id": "1",
"name": "Alice",
"email": "alice@test.com",
"createdAt": "2026-06-24T00:00:00Z"
}
}
}
assert result == snapshot, f"Snapshot mismatch: {json.dumps(result, indent=2)}"
print("Snapshot test passed")
Testing Error Handling
GraphQL returns errors in a structured format — test them explicitly:
def test_not_found():
query = "{ user(id: 99999) { id name } }"
result = run_query(query)
assert "errors" in result
assert any("not found" in e["message"].lower() for e in result["errors"])
assert result["data"]["user"] is None
print("Not found error test passed")
def test_unauthorized():
query = "{ adminPanel { settings } }"
result = run_query(query)
assert "errors" in result
assert any("unauthorized" in e["message"].lower() or "not authorized" in e["message"].lower()
for e in result["errors"])
print("Authorization error test passed")
test_not_found()
test_unauthorized()
Practice Questions
1. How is GraphQL API testing different from REST API testing?
GraphQL has a single endpoint and flexible queries. You test query structure, resolver logic, and schema types rather than fixed URL paths and status codes.
2. What is schema introspection and why is it useful for testing?
Introspection queries return the complete schema definition. You can use it to automatically validate that the schema matches your expected type structure.
3. How do you test GraphQL error handling?
GraphQL returns errors in a structured errors array alongside data. Test for specific error messages, error codes, and null data fields.
4. What is N+1 in GraphQL and how do you test for it?
N+1 occurs when a resolver makes a database query for each item in a list. Test by enabling query logging and checking that list queries produce a single batch query.
Challenge: Build a GraphQL API test suite for an e-commerce schema with types: Product, Order, Customer. Test: product search with filters, order creation with validation, customer profile update, schema introspection for all types, and error handling for out-of-stock products.
FAQ
What's Next
Built by the developers of Doda Browser, DodaZIP, and Durga Antivirus Pro.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro