Extract query function from GraphQLTestCase making it possible to use in a pytest fixture (#1015)

This commit is contained in:
Nikolai Røed Kristiansen 2020-08-05 21:24:16 +02:00 committed by GitHub
parent 97de26bf2e
commit 2308965658
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 132 additions and 34 deletions

View File

@ -1,6 +1,9 @@
Testing API calls with django
=============================
Using unittest
--------------
If you want to unittest your API calls derive your test case from the class `GraphQLTestCase`.
Your endpoint is set through the `GRAPHQL_URL` attribute on `GraphQLTestCase`. The default endpoint is `GRAPHQL_URL = "/graphql/"`.
@ -12,12 +15,8 @@ Usage:
import json
from graphene_django.utils.testing import GraphQLTestCase
from my_project.config.schema import schema
class MyFancyTestCase(GraphQLTestCase):
# Here you need to inject your test case's schema
GRAPHQL_SCHEMA = schema
def test_some_query(self):
response = self.query(
'''
@ -82,3 +81,38 @@ Usage:
# Add some more asserts if you like
...
Using pytest
------------
To use pytest define a simple fixture using the query helper below
.. code:: python
# Create a fixture using the graphql_query helper and `client` fixture from `pytest-django`.
import pytest
from graphene_django.utils.testing import graphql_query
@pytest.fixture
def client_query(client)
def func(*args, **kwargs):
return graphql_query(*args, **kwargs, client=client)
return func
# Test you query using the client_query fixture
def test_some_query(client_query):
response = graphql_query(
'''
query {
myModel {
id
name
}
}
''',
op_name='myModel'
)
content = json.loads(response.content)
assert 'errors' not in content

View File

@ -6,6 +6,7 @@ from mock import patch
from ..utils import camelize, get_model_fields, GraphQLTestCase
from .models import Film, Reporter
from ..utils.testing import graphql_query
def test_get_model_fields_no_duplication():
@ -58,3 +59,29 @@ def test_graphql_test_case_op_name(post_mock):
"operationName",
"QueryName",
) in body.items(), "Field 'operationName' is not present in the final request."
@pytest.mark.django_db
@patch("graphene_django.utils.testing.Client.post")
def test_graphql_query_case_op_name(post_mock):
graphql_query("query { }", op_name="QueryName")
body = json.loads(post_mock.call_args.args[1])
# `operationName` field from https://graphql.org/learn/serving-over-http/#post-request
assert (
"operationName",
"QueryName",
) in body.items(), "Field 'operationName' is not present in the final request."
@pytest.fixture
def client_query(client):
def func(*args, **kwargs):
return graphql_query(*args, client=client, **kwargs)
return func
def test_pytest_fixture_usage(client_query):
response = graphql_query("query { test }")
content = json.loads(response.content)
assert content == {"data": {"test": "Hello World"}}

View File

@ -2,6 +2,63 @@ import json
from django.test import TestCase, Client
DEFAULT_GRAPHQL_URL = "/graphql/"
def graphql_query(
query,
op_name=None,
input_data=None,
variables=None,
headers=None,
client=None,
graphql_url=None,
):
"""
Args:
query (string) - GraphQL query to run
op_name (string) - If the query is a mutation or named query, you must
supply the op_name. For annon queries ("{ ... }"),
should be None (default).
input_data (dict) - If provided, the $input variable in GraphQL will be set
to this value. If both ``input_data`` and ``variables``,
are provided, the ``input`` field in the ``variables``
dict will be overwritten with this value.
variables (dict) - If provided, the "variables" field in GraphQL will be
set to this value.
headers (dict) - If provided, the headers in POST request to GRAPHQL_URL
will be set to this value.
client (django.test.Client) - Test client. Defaults to django.test.Client.
graphql_url (string) - URL to graphql endpoint. Defaults to "/graphql".
Returns:
Response object from client
"""
if client is None:
client = Client()
if not graphql_url:
graphql_url = DEFAULT_GRAPHQL_URL
body = {"query": query}
if op_name:
body["operationName"] = op_name
if variables:
body["variables"] = variables
if input_data:
if variables in body:
body["variables"]["input"] = input_data
else:
body["variables"] = {"input": input_data}
if headers:
resp = client.post(
graphql_url, json.dumps(body), content_type="application/json", **headers
)
else:
resp = client.post(
graphql_url, json.dumps(body), content_type="application/json"
)
return resp
class GraphQLTestCase(TestCase):
"""
@ -9,19 +66,12 @@ class GraphQLTestCase(TestCase):
"""
# URL to graphql endpoint
GRAPHQL_URL = "/graphql/"
# Here you need to set your graphql schema for the tests
GRAPHQL_SCHEMA = None
GRAPHQL_URL = DEFAULT_GRAPHQL_URL
@classmethod
def setUpClass(cls):
super(GraphQLTestCase, cls).setUpClass()
if not cls.GRAPHQL_SCHEMA:
raise AttributeError(
"Variable GRAPHQL_SCHEMA not defined in GraphQLTestCase."
)
cls._client = Client()
def query(self, query, op_name=None, input_data=None, variables=None, headers=None):
@ -43,28 +93,15 @@ class GraphQLTestCase(TestCase):
Returns:
Response object from client
"""
body = {"query": query}
if op_name:
body["operationName"] = op_name
if variables:
body["variables"] = variables
if input_data:
if variables in body:
body["variables"]["input"] = input_data
else:
body["variables"] = {"input": input_data}
if headers:
resp = self._client.post(
self.GRAPHQL_URL,
json.dumps(body),
content_type="application/json",
**headers
return graphql_query(
query,
op_name=op_name,
input_data=input_data,
variables=variables,
headers=headers,
client=self._client,
graphql_url=self.GRAPHQL_URL,
)
else:
resp = self._client.post(
self.GRAPHQL_URL, json.dumps(body), content_type="application/json"
)
return resp
def assertResponseNoErrors(self, resp):
"""