Testing old-school APIs is super fun and easy. Frameworks like Django have a huge emphasis of testing; and make it very easy to do so.
But it is 2017, and GraphQL is changing the way that we write APIs. In particular, Graphene Django is an easy to use library for writing GraphQL APIs within Django.
However, Graphene Django doesn't include a testing guide! But fear not, testing is easy, simple and clear.
Executing a GraphQL query is very simple - you just POST it to your endpoint and get JSON back. To make it even easer in test, we use a little helper class to abstract away the details:
import json
from django.test import TestCase
from django.test import Client
# Inherit from this in your test cases
class GraphQLTestCase(TestCase):
def setUp(self):
self._client = Client()
def query(self, query: str, op_name: str = None, input: dict = 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 (dict) - If provided, the $input variable in GraphQL will be set
to this value
Returns:
dict, response from graphql endpoint. The response has the "data" key.
It will have the "error" key if any error happened.
'''
body = {'query': query}
if op_name:
body['operation_name'] = op_name
if input:
body['variables'] = {'input': input}
resp = self._client.post('/graphql', json.dumps(body),
content_type='application/json')
jresp = json.loads(resp.content.decode())
return jresp
def assertResponseNoErrors(self, resp: dict, expected: dict):
'''
Assert that the resp (as retuened from query) has the data from
expected
'''
self.assertNotIn('errors', resp, 'Response had errors')
self.assertEqual(resp['data'], expected, 'Response has correct data')
Then you just test! You can write the same style tests as if you were using the excellent Django Rest Framework, but with GraphQL. Here's a basic example of a query:
def test_is_logged_in(self):
resp = self.query('{ isLoggedIn }')
self.assertResponseNoErrors(resp, {'isLoggedIn': False})
Or a more complex example with a mutation:
def test_login_mutation_successful(self):
User.objects.create(username='test', password='hunter2')
resp = self.query(
# The mutation's graphql code
'''
mutation logIn($input: LogInInput!) {
logIn(input: $input) {
success
}
}
''',
# The operation name (from the 1st line of the mutation)
op_name='logIn',
input={'username': 'test', 'password': 'hunter2'}
)
self.assertResponseNoErrors(resp, {'logIn': {'success': True}})
At LearntEmail, we're really excited to be using GraphQL for our API. Testing is so important stable software - so good testing tools are a must.
Feel free to tweet to us @LearntEmail with your thoughts on GraphQL testing, and subscribe (below) to follow our GraphQL journey & experiences.
I hope you enjoyed this article. Contact me if you have any thoughts or questions.
© 2015—2024 Sam Parkinson