Skip to content
This repository
Browse code

Merge branch 'kipanshi/R104_test_runner_storing_results_in_test_db'

  • Loading branch information...
commit e98ce282b2fef7b0325cf7e34c4f33dd03b2034e 2 parents cb13865 + 8e3d3f1
Ask Solem Hoel ask authored
62 djcelery/contrib/test_runner.py
... ... @@ -1,8 +1,15 @@
1 1 from __future__ import absolute_import
2 2
  3 +from uuid import uuid4
  4 +from datetime import datetime
  5 +
3 6 from django.conf import settings
4 7 from django.test.simple import DjangoTestSuiteRunner
5 8
  9 +from celery.task import Task
  10 +from djcelery.models import TaskState
  11 +
  12 +
6 13 USAGE = """\
7 14 Custom test runner to allow testing of celery delayed tasks.
8 15 """
@@ -22,3 +29,58 @@ def setup_test_environment(self, **kwargs):
22 29 super(CeleryTestSuiteRunner, self).setup_test_environment(**kwargs)
23 30 settings.CELERY_ALWAYS_EAGER = True
24 31 settings.CELERY_EAGER_PROPAGATES_EXCEPTIONS = True # Issue #75
  32 +
  33 +
  34 +class CeleryTestSuiteRunnerStoringResult(DjangoTestSuiteRunner):
  35 + """This custom test suite runner make some preliminary
  36 + monkey-patching allowing storing result of Celery task execution
  37 + in ``djcelery.models.TaskState`` model. Tasks run eagerly.
  38 +
  39 + Exceptions is turned on. If you need to test ``on_failure``
  40 + behavior, you should monkey-patch in your test:
  41 + ``settings.CELERY_EAGER_PROPAGATES_EXCEPTIONS = False``
  42 +
  43 + USAGE:
  44 + In ``settings.py``:
  45 + TEST_RUNNER = 'djcelery.contrib.test_runner.' \
  46 + 'CeleryTestSuiteRunnerStoringResult'
  47 +
  48 + In ``tests.py``:
  49 + from djcelery.models import TaskState
  50 + TaskState.object.filter(state='SUCCESS', args__contains='test')
  51 +
  52 + """
  53 + def setup_test_environment(self, **kwargs):
  54 + """ Setting up test environment. """
  55 +
  56 + # Monkey-patch Task.on_success() method
  57 + def on_success_patched(self, retval, task_id, args, kwargs):
  58 +
  59 + TaskState.objects.create(task_id=uuid4().hex,
  60 + state="SUCCESS",
  61 + name=self.name,
  62 + result=retval,
  63 + args=args,
  64 + kwargs=kwargs,
  65 + tstamp=datetime.now())
  66 + Task.on_success = classmethod(on_success_patched)
  67 +
  68 + # Monkey-patch Task.on_failure() method
  69 + def on_failure_patched(self, exc, task_id, args, kwargs, einfo):
  70 +
  71 + TaskState.objects.create(task_id=uuid4().hex,
  72 + state="FAILURE",
  73 + name=self.name,
  74 + result=einfo,
  75 + args=args,
  76 + kwargs=kwargs,
  77 + tstamp=datetime.now())
  78 + Task.on_failure = classmethod(on_failure_patched)
  79 +
  80 + # Call parent's version
  81 + super(CeleryTestSuiteRunnerStoringResult,
  82 + self).setup_test_environment(**kwargs)
  83 +
  84 + # Tell celery run tasks synchronously
  85 + settings.CELERY_ALWAYS_EAGER = True
  86 + settings.CELERY_EAGER_PROPAGATES_EXCEPTIONS = True # Issue #75
33 docs/cookbook/unit-testing.rst
Source Rendered
@@ -20,10 +20,16 @@ Using a custom test runner to test with celery
20 20
21 21 If you're going the ``CELERY_ALWAYS_EAGER`` route, which is probably better than
22 22 just never testing some parts of your app, a custom Django test runner does the
23   -trick. Celery provides a simple test runner, but it's easy enough to roll your
24   -own if you have other things that need to be done.
  23 +trick. Celery provides two simple test runner classes, but it's easy enough
  24 +to roll your own if you have other things that need to be done.
25 25 http://docs.djangoproject.com/en/dev/topics/testing/#defining-a-test-runner
26 26
  27 +``CeleryTestSuiteRunner`` eagerly runs all tasks in tests, but result is not stored anywhere.
  28 +``CeleryTestSuiteRunnerStoringResult`` --- this test runner in addition stores
  29 +result of task execution or failure in ``djcelery.models.TaskState`` model,
  30 +likewise django-celery does during normal operation when workers
  31 +and ``celerycam`` are launched.
  32 +
27 33 For this example, we'll use the ``djcelery.contrib.test_runner`` to test the
28 34 ``add`` task from the `User Guide: Tasks`_ examples in the Celery
29 35 documentation.
@@ -34,13 +40,15 @@ To enable the test runner, set the following settings:
34 40
35 41 .. code-block:: python
36 42
37   - TEST_RUNNER = 'djcelery.contrib.test_runner.CeleryTestSuiteRunner'
  43 + TEST_RUNNER = 'djcelery.contrib.test_runner.' \
  44 + 'CeleryTestSuiteRunnerStoringResult'
38 45
39 46 Then we can put the tests in a ``tests.py`` somewhere:
40 47
41 48 .. code-block:: python
42 49
43 50 from django.test import TestCase
  51 + from djcelery.models import TaskState
44 52 from myapp.tasks import add
45 53
46 54 class AddTestCase(TestCase):
@@ -53,6 +61,25 @@ Then we can put the tests in a ``tests.py`` somewhere:
53 61 self.assertEquals(result.get(), 16)
54 62 self.assertTrue(result.successful())
55 63
  64 + # Run another task
  65 + add.delay(4, 4)
  66 +
  67 + # Assert we have 2 task results in the test database
  68 + self.assertEqual(TaskState.objects.count(), 2)
  69 +
  70 + # Assert results
  71 + self.assertEqual([task_state.result for task_state
  72 + in TaskState.objects.all()], [16, 8])
56 73
57 74 This test assumes that you put your example ``add`` task in ``maypp.tasks``
58 75 so adjust the import for wherever you put the class.
  76 +
  77 +If you're going to use
  78 +``'djcelery.contrib.test_runner.CeleryTestSuiteRunnerStoringResult``
  79 +then if your task will raise exception it will propagate through.
  80 +If you need to test ``on_failure`` behavior of your task,
  81 +set ``settings.CELERY_EAGER_PROPAGATES_EXCEPTIONS`` to ``False``:
  82 +
  83 +.. code-block:: python
  84 +
  85 + settings.CELERY_EAGER_PROPAGATES_EXCEPTIONS = False

0 comments on commit e98ce28

Please sign in to comment.
Something went wrong with that request. Please try again.