question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

properly reset databases on tests teardown

See original GitHub issue

Currently multiple databases are supported by creating instance of Migrator for each database, but only default database is cleaned at the end of test - https://github.com/wemake-services/django-test-migrations/blob/master/django_test_migrations/migrator.py#L77

Also using migrate management command is not the best idea when it comes to performance, because there is no need to apply all unapplied migrations just before the next test, which should start with clean state. Django’s TestCase uses flush management command to clean databases after test.

We need to reuse Django’s code responsible for cleaning database on test teardown (or establish our own way to do that) and fix Migrator.reset() method to clean Migrator.database instead of default one.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Reactions:1
  • Comments:22 (9 by maintainers)

github_iconTop GitHub Comments

2reactions
skarzicommented, Apr 11, 2020

@asfaltboy I have digged into Django’s migrations deeper and had some answers for your problem, but also many new concerns that I’d like to discuss.

Note that I tried testing #46 locally and I’m having issues with dependency migrations not being applied (while they are being applied in current 0.2.0 ).

This issue is related to how Django built migrations’ plan. In 0.2.0 migration’s test setup/assert/teardown flow looks like below:

(NOTE: in both cases, before running tests, django calls migrate command to migrate all forwards).

  1. Use migration executor to migrate backward to migrate_from - migrating backward to migrate_from unapplies only migrations that are higher in migrations plan than migrate_from
  2. Create some db models instances to test migrate_to on them
  3. Migrate forward to migrate_to
  4. Do assertions
  5. Call migrate command to migrate all forwards

Flow implemented in #46 looks like below:

  1. Drop all model’s tables
  2. Flush django_migrations table
  3. Migrate forward to migrate_from - here migrations are applied on clean database and everything goes forward, so only migrations that are dependencies of migrate_from will be applied
  4. Create some db models instances to test migrate_to on them
  5. Migrate forward to migrate_to
  6. Do assertions
  7. Call migrate command to migrate all forwards

Let’s imagine we have 2 apps: some_app and other_app. some_app has following migrations:

  • 0009_do_some_stuff - all migrations from initial to this one are not dependent in anyway on other_app
  • 0010_do_some_stuff_dependent_on_other_app - this is the first migration that depends on other_app

other_app is self-sufficient when it comes to migrations (like e.g. django.contrib.sites) and it’s much lower in migrations plan than some_app.

Then let’s imagine we are testing migration 0010, so migrate_from is 0009 and migrate_to is 0010. Let’s focus on preparation step where some testing db models instances are created.

In 0.2.0 we will have access to models from other_app, because we are migrating backward and only migrations higher in the plan than migrate_before will be unapplied But in #46 we won’t be able to access other_app models, because we are migrating only forward to migrate_from which is not dependent on other_app.

The problem is more trickier than I thought 😦 Solution from 0.2.0 is not ideal because it’s not similar to how we apply migrations on production, however it’s hard to implement production like solution for migration’s test flow.

Yesterday I was experimenting with creating migrations plan manually starting from one of:

  • plan generated for migrate_to targets
  • complete plan generated for clean db

and then truncating such plan on migrate_before migrations, to make it more like on production (avoid migrating backwards) and preserve behaviour from 0.2.0. It’s quite “magical”/complicated solution, however I can clean it and push (but give me few days) so we can discuss it.

2reactions
asfaltboycommented, Apr 10, 2020

Hi @skarzi thanks for investing much time into this, this is indeed a tough issue to solve.

I was thinking about this a bit more, and it seems that, typically, the reason data migrations fail to be re-applied in teardown is due to “primary key sequence” mismatch. I see that in your PR #46 you implement get_django_migrations_table_sequences to keep track of the ids … do you think it’s possible to simplify this by using django.test.TransactionTestCase.reset_sequences (also supported in pytest-django)?

Note that I tried testing #46 locally and I’m having issues with dependency migrations not being applied (while they are being applied in current 0.2.0 ). I was not able to overcome this by specifying all the related apps migrations (I gave up mid-way), but even if I did it would not be ideal. How come this is not the same behavior as on 0.2.0, I thought #46 only fixes the teardown?

Read more comments on GitHub >

github_iconTop Results From Across the Web

The argument against clearing the database between tests
avoid tearing down/recreating static data such as lookup tables; track which tables have been touched and don't clean untouched ones; turn off ...
Read more >
Reset database at the end of test - symfony - Stack Overflow
I want to reset my test database after each test but somehow can't find a way to do it. Can delete the data...
Read more >
tearDown does not delete the test data before to migrate back ...
If there was a way of saying "restore DB state such that it will pass all future migrations", then absolutely. But I am...
Read more >
Setup and Teardown - Jest
If you have some work you need to do repeatedly for many tests, you can use beforeEach and afterEach hooks. For example, let's...
Read more >
testing - How to reset state of exernal services when running ...
For example, if you have a database cleanup method that empties the database, it's perfectly fine for that to bypass your domain logic...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found