Hi, I'm Sam Parkinson

Testing GraphQL with Graphene Django

The missing guide

By Sam Parkinson, 04 March 2017; view other posts

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.

Our helper class

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')

Copy and paste!

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}})

A GraphQL future

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.


Comments, thoughts? Mail them to sam@sam.today. I would love to hear them!

Related posts

View all posts
Keeping Python projects secure on GitLab
Pinning projects to the very latest
Read post
Local Politicians Meet InfoSec - a Wordpress Disaster
The article that I didn't want to have to write
Read post
Derivations 102 - Learning Nix pt 4
Taking advantage of the fact Nix is a programming language
Read post
Creating a super simple derivation - Learning Nix pt 3
Wrapping some shell scripts
Read post
So Variables are a Thing - Learning Nix pt 2
Taking advantage of the fact Nix is a programming language
Read post
NSDC 2016 Topics
Digitizing the motions from National Schools Debating Championships 2016
Read post