Opened 5 years ago

Closed 5 years ago

Last modified 5 months ago

#31612 closed New feature (wontfix)

Running tests with --keepdb messy to flush.

Reported by: Jarek Glowacki Owned by: nobody
Component: Testing framework Version: dev
Severity: Normal Keywords: test keepdb
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

We run tests with --keepdb flag by default. If there are changes that require dropping the test database, we run the testsuite once without the keepdb flag.
However this not only drops the db before tests, but also drops it after tests too.
So next time we run the testsuite with the --keepdb flag, the database is recreated and migrations are run once more (unnecessarily).

It feels very clunky.

It all works as initially intended in https://code.djangoproject.com/ticket/20550:

I'd like to implement a similar feature in Django. In the light of my first experience, I suggest a simpler API. I would add a single flag --keepdb. When this flag is set:

  • at the beginning of the tests, if the database already exists, Django doesn't ask to delete it; it goes ahead and reuses it;
  • at the end of the tests, Django doesn't drop the database.

The original ticket author mentioned they'd implemented the --nocreatedb and --nodropdb options in their own project, prior to --keepdb existing, so they didn't have this issue.
I like the simplification that django offers and am not proposing to split keepdb into two separate flags, however offering a flag that enables either of the following would greatly unclunk --keepdbs use:

  • "Don't drop db after running tests." (when --keepdb is off). Something like --preservedb, --nodropdb, etc.
  • "Drop db prior to running tests." (when --keepdb is on). Something like --refreshdb, etc.

Yes, it's an extra flag, but it doesn't work the same way as --nocreatedb and --nodropdb, because for the majority of runs users just need to pass one flag (--keepdb), rather than multiple.

Another solution could be to offer a separate mcommand called droptestdb or something similar -- it's sole role would be to clean up anything that was left by the last --keepdb, so that the next one can run with a fresh db.

Finally, changing behaviour on --keepdb so that it somehow _knows_ when to prompt to start from scratch when it feels there is something not lining up in the migrations could be another way to go. Solution would be very magic, and maybe not great at guessing when to prompt, but would save the user from having to learn any of the other proposed options.

In short, --keepdb is flawed in how it requires TWO rounds of dropping/creating the db and running migrations (running without keepdb, then with keepdb again) to refresh a database.
I've put forward a few ideas on how to address this, but none particularly compelling.

Any thoughts?

Change History (3)

comment:1 by Mariusz Felisiak, 5 years ago

Resolution: wontfix
Status: newclosed
Type: UncategorizedNew feature
Version: 3.0master

I don't agree that --keepdb is clunky it works as intended.

If there are changes that require dropping the test database.

I think that's something unusual. Everything will work without an extra roundtrip if you'll control these changes with migrations and without dropping the test database. So I would say that an issue is in your workflow rather than in Django itself. Running tests wasn't designed to drop a test database when something terrible happens. You use mix of --keepdb on/off calls to do this, but it's not a "supported" flow.

Finally, changing behaviour on --keepdb so that it somehow _knows_ when to prompt to start from scratch when it feels there is something not lining up in the migrations could be another way to go. Solution would be very magic, and maybe not great at guessing when to prompt, but would save the user from having to learn any of the other proposed options.

I think you've already answered that it's not feasible by using words like it somehow _knows_ and very magic.

comment:2 by Jarek Glowacki, 5 years ago

Sorry, I should've provided some examples for when dropping the test db might be necessary:

  • Doctoring an existing migration on a local branch. eg. I run tests on a local branch, applying a migration i've just added. I notice the migration is wrong and wish to change it before pushing it upstream. Running the tests again won't pick up my change. And to my knowledge I can't just unapply the migration like i can with the migrate mcommand.
  • Rebasing migrations. eg. I've got a stale PR with a migration on it. I rebase my work and rename the migration and its dependencies to sit at the end of the list. Local test db still thinks I've already applied said changes and falls over trying to apply them a second time. (Yes I could just add a merge migration here, but it's unnecessary clutter if the migration exists only on my PR. And i don't think faking migrations is possible here, like it is with migrate.)

Are such workflows out of the ordinary?

Anyway, if this still isn't sufficiently convincing, won't argue further.
Will just add some custom code to do it in our own product I guess..

Thanks for the quick triage!

comment:3 by tinodb, 5 months ago

I must say I run into the same cases Jarek above runs into, which are mainly around migrations. Either when creating them, or when switching branches. I'm not so sure that is a very weird workflow for a larger team working on a Django project?

I would say a --createdb (or --recreatedb) flag (which would drop the db(s) upfront, without asking for input) would be very complementary to --keepdb and I miss it quite often. (I usually check new Django release to see if it has been added by chance :).

pytest-django has this as well: https://pytest-django.readthedocs.io/en/latest/database.html#create-db-force-re-creation-of-the-test-database.

Note: See TracTickets for help on using tickets.
Back to Top