Speed Dajngo tests for CI/CD and (locally).
Tags: django, testing
Published: 2022-12-17 21:08:42

After some experimentation on how to speed up Django tests 
here are my findings sorted in no particular order 

# Migration Zero
 
In simple words, this method is about regularly removing all migration files and recreating them, so migrations are compact.
and here's a good [article](https://medium.com/@xavier.dubuc/migrations-zero-or-how-to-handle-migrations-on-a-large-django-project-643627938449/) explaining it in details.

### Pros 
- Your workflow stays the same whether in testing or development.
- Speeds up tests and dev environment creations as well.

### Cons 
- Tedious and error-prone and maybe a little unintuitive.
- Requires regular maintenance.
- In production environments, you need to do some faking so the newly created migrations don't affect your existing DB.

# Squash Migrations
This is a utility (command) by Django to merge some migrations into one, you can read about it from Django [docs](https://docs.djangoproject.com/en/4.1/topics/migrations/#squashing-migrations).

### Pros 
- It's managed and supported by the framework itself.
- You are in control of which migrations are to be merged (ranges of continuous migrations).
- Speeds up Tests and dev environment creation as well.

### Cons
- It works perfectly with a small number of migrations, However, with a large number and complex migrations, things start to get a bit tedious. Cause you have to fix manually the circular dependencies, adjust, copy, replace, data migrations, and more. Which could be challenging in some cases.

# DB dumps
This is like using `--keepdb`, which is come in handy while working locally, and not many changes on the schema level between multiple test cycles, which is not the case most of the time. why I said dumps, cause in my case it was more speeding for CI/CD than it's locally. So the suggestion was to take a more recent dump of an empty DB and provide it to the pipeline to execute the tests on, (via containers).

### Pros
- Straight forward solution.

### Cons
- Only speeds up tests on the ci/cd pipeline. and left local with only the `--keepdb` option (unless you would to use that container locally as well).
- Still needs regular maintenance to keep the DB dumps as up-to-date as possible to keep the wheels rolling at the same speed.

# Disable Migrations for tests
This as the name suggests, disables running migrations in case of tests using this `MIGRATE=False` [flag](https://docs.djangoproject.com/en/3.2/ref/settings/#migrate), and by doing that Django creates the DB directly from the model which in case of hundreds of migrations is way faster.

The caveat here is if your DB depends somehow on data migration ran at some point, then you need to run these migrations (functions) manually after creating the models and before running the test, One way to achieve that is by running a custom test runner.

### Pros
- It's very fast.
- Requires less or no effort to maintain.

### Cons
- Speeds up tests only, dev environment is left without luck.
- Need to be careful in case of data migration affects your tests, as they aren't going to run out of the box and you need to run them yourself, also ensure that they don't run over and over again and cause data inconstancy or violate schema rules like uniqueness, etc...

# Conclusion:
There are multiple ways to enhance your test speed (from a DB creation perspective) each with its pros and cons and shall pick the best for your case.

Please let me know your opinions and if you have more approaches.