kitware-resonant / cookiecutter-resonant

Apache License 2.0
11 stars 6 forks source link

Add example of directly calling Celery tasks in testing #74

Open brianhelba opened 4 years ago

brianhelba commented 4 years ago

To the extent this requires settings changes to Celery, consider updating:

mcovalt commented 4 years ago

There are three approaches that I know of to test with Celery:

  1. task_always_eager. Executes all tasks sequentially within the delay() call. Not recommended.
  2. Embed a worker as thread. This is essentially what Celery's pytest fixtures do. They use a context manager to embed and shutdown a worker. I've used this approach before in Django 2.x, but it won't work with Django 3.x. Or, perhaps, Django 3.x exposes why it was a bad idea in Django 2.x. With Django's newfound focus on asynchronous design, they intentionally crash the application when multiple threads try to get a new connection to a database. In theory I don't see why this is unsafe, but I am guessing Django has some non-thread-safe state for the database.
  3. Spawn a worker process. I would say this is the most realistic way to do an integration test with Celery, but presents a few challenges not present in the thread-based approach. We'd need to make sure...
    • ... pytest can get coverage in the subprocess. Seems doable, but maybe finnicky.
    • ... changed Django settings (e.g. DATABASES) are propagated to the subprocess.
    • ... subprocess are collected and shutdown nicely.

An ideal solution would be to have a context manager handle number three. Additionally, it should create an ephemeral queue per pool. This context manager would be nice to have for a couple things: