hypothesis-graphql
Generate GraphQL queries from your schema and test your server with them
hypothesis-graphql gives you Hypothesis strategies that build queries and mutations from a GraphQL schema.
Each generated operation selects a random subset of fields at random depth and fills arguments with random values.
For a ready-made tool, try Schemathesis: it runs on top of this library and reports server crashes without any test code.
Usage
from_schema takes a schema and returns a strategy that yields queries and mutations as strings:
from hypothesis import given
from hypothesis_graphql import from_schema
import requests
# A schema string or a `graphql.GraphQLSchema` instance
SCHEMA = """
type Book {
title: String
author: Author
}
type Author {
name: String
books: [Book]
}
type Query {
getBooks: [Book]
getAuthors: [Author]
}
type Mutation {
addBook(title: String!, author: String!): Book!
addAuthor(name: String!): Author!
}
"""
@given(from_schema(SCHEMA))
def test_graphql(query):
# Generates operations like:
#
# {
# getBooks {
# title
# }
# }
#
# mutation {
# addBook(title: "H4Z\u7869", author: "\u00d2"){
# title
# }
# }
response = requests.post("http://127.0.0.1/graphql", json={"query": query})
assert response.status_code == 200
assert response.json().get("errors") is None
To generate only one kind of operation, use hypothesis_graphql.queries or hypothesis_graphql.mutations.
Customization
Pass fields to limit which root fields appear in generated operations:
@given(from_schema(SCHEMA, fields=["getAuthors"]))
def test_graphql(query):
# Only `getAuthors` will be generated
...
Two arguments control generated strings:
allow_x00(defaultTrue): set it toFalseto keep\x00out of strings. Some web servers reject requests that contain it.codec(defaultutf-8): generated strings only contain characters this codec can encode. Use"ascii"to stay in the ASCII range.
@given(from_schema(SCHEMA, allow_x00=False, codec="ascii"))
def test_graphql(query):
assert "\0" not in query
query.encode("ascii")
Set allow_null=False to keep null out of argument values, including nested input fields and list items.
Built-in scalars (Int, Float, String, ID, Boolean) work out of the box.
For a custom scalar such as Date, pass a strategy that generates AST nodes for it:
from hypothesis import strategies as st, given
from hypothesis_graphql import from_schema, nodes
SCHEMA = """
scalar Date
type Query {
getByDate(created: Date!): Int
}
"""
@given(
from_schema(
SCHEMA,
custom_scalars={"Date": st.dates().map(nodes.String)},
)
)
def test_graphql(query):
# Example:
#
# { getByDate(created: "2000-01-01") }
#
...
Without a strategy, hypothesis-graphql skips optional arguments of that type and raises hypothesis.errors.InvalidArgument if a required argument uses it.
hypothesis_graphql.nodes has helpers that build value nodes:
String->graphql.StringValueNode(converts the value withstr())Float->graphql.FloatValueNodeInt->graphql.IntValueNodeObject->graphql.ObjectValueNodeList->graphql.ListValueNodeBoolean->graphql.BooleanValueNodeEnum->graphql.EnumValueNodeNull->graphql.NullValueNode(a constant, not a function)
Use them in map calls: graphql.StringValueNode and friends accept keyword arguments only.
Negative Testing
Pass mode=Mode.NEGATIVE to generate operations your server must reject:
from hypothesis import given
from hypothesis_graphql import queries, Mode
import requests
SCHEMA = """
type Query {
getUser(id: Int!, name: String!): User
}
type User {
id: Int!
name: String!
}
"""
@given(queries(SCHEMA, mode=Mode.NEGATIVE))
def test_server_rejects_invalid_queries(query):
# Each query violates the schema in exactly one of these ways:
# - a value of the wrong type (a string for an `Int`)
# - a missing required argument
# - an `Int` outside the 32-bit range
# - `null` for a non-null argument
# - an unknown enum value
# - an input object without one of its required fields
response = requests.post("http://127.0.0.1/graphql", json={"query": query})
# The server must answer with an error status or an `errors` list
if response.status_code == 200:
assert "errors" in response.json()
queries, mutations, and from_schema all accept mode.
If no argument in the schema allows any of these violations, negative mode raises InvalidArgument.
License
hypothesis-graphql is available under the MIT license.
By contributing, you agree to license your contributions under it.
Metadata
Release files for hypothesis-graphql 0.13.4
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| hypothesis_graphql-0.13.4.tar.gz | 751.8 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hypothesis_graphql-0.13.4-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 775.3 kB
Release files / hypothesis_graphql-0.13.4.tar.gz
| Download URL | hypothesis_graphql-0.13.4.tar.gz |
|---|---|
| Size | 751.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
bd9c411db327528c442da9a9f5e2bccf213e9695d57f9eb7e176600841ae045b
|
|
BLAKE2b-256 checksum How to use checksums |
62600c374a8964825b585119c2f63fc4fab80474aa7b900305fe10d52daa1d89
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
Hatch/1.18.1 {"ci":true,"cpu":"x86_64","distro":{"id":"noble","libc":{"lib":"glibc","version":"2.39"},"name":"Ubuntu","version":"24.04"},"implementation":{"name":"CPython","version":"3.14.8"},"installer":{"name":"hatch","version":"1.18.1"},"openssl_version":"OpenSSL 3.0.13 30 Jan 2024","python":"3.14.8","system":{"name":"Linux","release":"6.17.0-1022-azure"}} HTTPX2/2.15.1
|
Release files / hypothesis_graphql-0.13.4-py3-none-any.whl
| Download URL | hypothesis_graphql-0.13.4-py3-none-any.whl |
|---|---|
| Size | 23.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
17168be0a40a9ca9fc24a5c76f8500ee4bc34f257a6a2a61f7c4090974e82d5b
|
|
BLAKE2b-256 checksum How to use checksums |
1b67b435f512aaeb32320bd53aaf5a4beb556f5f0353c6b52458c3db0aa03bba
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
Hatch/1.18.1 {"ci":true,"cpu":"x86_64","distro":{"id":"noble","libc":{"lib":"glibc","version":"2.39"},"name":"Ubuntu","version":"24.04"},"implementation":{"name":"CPython","version":"3.14.8"},"installer":{"name":"hatch","version":"1.18.1"},"openssl_version":"OpenSSL 3.0.13 30 Jan 2024","python":"3.14.8","system":{"name":"Linux","release":"6.17.0-1022-azure"}} HTTPX2/2.15.1
|
Security for hypothesis-graphql 0.13.4
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.