GraphQL: Testing Plan and Risks
2.7 Testing Plan
Schema Tests
Test Case
What to Check
Type validation
All types resolve correctly, required fields marked with !
Field types match
String fields return strings, Int fields return integers
Breaking changes detection
Removed fields, changed types, renamed fields
Schema diffing
Use GraphQL Inspector to compare schema versions
Run schema tests on every PR. Breaking changes should block the merge.
Query Validation Tests
Test that the server rejects bad queries before execution:
Syntax errors — malformed query string returns a clear parse error.
Schema mismatch — query for non-existent field returns validation error.
Type errors — wrong argument type (string instead of int) returns validation error.
Missing required arguments — omitting a ! argument returns validation error.
Unknown directives — using undefined directives returns validation error.
Each error response must include a human-readable message and the location in the query.
Resolver Tests
Unit test each resolver in isolation:
Mock context — provide fake database, fake auth, fake DataLoader.
Verify data — resolver returns expected data for valid input.
Error propagation — resolver throws an error, and it appears in response.errors with correct path.
Null handling — nullable fields return null gracefully, non-nullable fields propagate error up.
Authorization — resolver checks permissions before returning data.
Test
Setup
Expected Result
Depth limit
Query exceeding max depth
Rejected with clear error
Complexity limit
Query with high total cost
Rejected with score in error
Load test
N concurrent queries (e.g., 1000 rps)
p99 < 500ms, error rate < 1%
DataLoader batching
Query list with nested relations
SQL query count = 2, not N+1
Large response
Query returning 10,000 items
Response time < 2s
Security Tests
Introspection disabled in production — { __schema { types { name } } } returns error or empty result.
Query size limit — extremely large query body (>1MB) returns 413 or error.
Batching attack — sending 100 operations in one request is limited or rejected.
Field suggestions disabled — error messages do not suggest valid field names (information leak).
CSRF protection — mutations require proper headers or tokens.
Authorization Tests
Test that access control works at field level:
User Role
Requested Field
Expected Result
Admin
user.email
Returns email
Viewer
user.email
Returns null or error
Anonymous
user.email
Returns auth error
Owner
user.settings
Returns settings
Other user
user.settings
Returns null or error
Subscription Tests
Connection lifecycle — connect, subscribe, receive event, unsubscribe, disconnect.
Event delivery — create a mutation, verify subscription receives the event.
Filtering — subscribe to specific events only, verify other events are not received.
Reconnect — client disconnects, reconnects, re-subscribes. Verify it works.
Concurrent subscriptions — multiple active subscriptions on one connection.
2.8 Risks & Limitations
Risk
Impact
Mitigation
Query complexity explosion
Server CPU spike, slow responses
Depth + complexity limits
Deep query DoS
Server resource exhaustion
Query depth limit (max 10-15)
N+1 resolvers
Database overload, slow responses
Always use DataLoader
CPU-heavy execution
Higher latency than REST for simple cases
Persisted queries, query caching
Caching Risks
Risk
Impact
Mitigation
No HTTP caching
POST requests not cached by CDN/browser
Persisted queries with GET
Cache invalidation
Stale data shown to users
Normalized client cache, TTL
Architecture Risks
Risk
Impact
Mitigation
Schema complexity
Hard to maintain, slow to evolve
Modularization, federation
Tight coupling
Client queries tied to schema shape
Careful schema evolution, versioning
Rate limiting difficulty
Hard to limit per field or operation
Complexity-based rate limiting
Over-fetching by server
Resolvers fetch data client didn't ask for
Use info parameter in resolvers
Operational Risks
Monitoring — harder to monitor than REST because all requests go to one endpoint (/graphql). Solution: log operation names, use APM tools that understand GraphQL.
Error tracking — partial errors (200 status with errors in body) can be missed by standard monitoring. Solution: check errors array in every response.
Schema evolution — removing a field breaks clients. Solution: deprecate first, remove after migration period. Never rename fields — add new, deprecate old.
api
architecture
graphql