Testing Your Code

Asana does not provide a testing sandbox API (although you can request a “Non-Productive Use” Order Form from their API support email address to get an account for testing purposes). When testing the integration of your application with Asana, you will likely want to mock any connections to Asana that would write data to avoid creating a lot of junk data in Asana.

Some strategies for testing with django-asana are as follows:

  • Override the ASANA_ACCESS_TOKEN setting so that if your tests do reach out to Asana they will get an authentication error instead of writing bad data. This would be unnecessary if you follow the other steps, but by adding it to your TestCase, any new tests that do not mock your connections to Asana will fail loudly. If you want to test a read from Asana, you would not want to override your credentials.
  • Mock the connection itself. django-asana provides some mock responses you can test with.
  • When you need multiple mocks returned for database insertion, you will want them all to have unique ids to avoid integrity errors.
from unittest.mock import MagicMock, patch

from django.test import TestCase, override_settings
from unittest.mock import patch

def counter():
    count = 1
    while True:
        yield count
        count += 1


COUNTER = counter()


def get_task(**kwargs):
    if 'assignee' in kwargs:
        kwargs['assignee'] = {'gid': kwargs['assignee']}
    if 'parent' in kwargs:
        kwargs['parent'] = {'gid': kwargs['parent']}
    return task(**kwargs)


def new_task(**kwargs):
    """Returns a mock Asana response for a task create."""
    task_ = get_task(**kwargs)
    task_['gid'] = next(COUNTER)
    return task_


def update_task(*args):
    """Returns a mock Asana response for an update.

    update gets passed a tuple: (gid, dict)
    """
    kwargs = {key: value for key, value in args[1].items()}
    task_ = get_task(**kwargs)
    task_['gid'] = args[0]
    return task_


@override_settings(ASANA_ACCESS_TOKEN='foo')  # Assures your credentials are not real
class TestTask(TestCase):

    @patch('djasana.models.client_connect')
    def test_update_date_tasks(self, mock_connect):
        """Demonstrates how to mock for testing purposes."""
        mock_client = mock_connect.return_value
        mock_client.tasks.find_all.return_value = [task()]
        mock_client.tasks.create.side_effect = new_task
        mock_client.tasks.update.side_effect = update_task
        mock_client.tasks.set_parent.side_effect = new_task
        # Do something with those mocks