feat: MRTTestCase for unittest-based Django migration testing#61
Merged
Conversation
Setup section previously showed users they must write a test file. Restructured to lead with the zero-config value: configure MRTConfig and 6 safety tests appear automatically with no test files needed. Removed the duplicate "Built-in default tests" section buried in the lower half of the README.
Allows Django teams not using pytest to test migration rollback safety
with manage.py test, matching the API style of django-test-migrations.
from pytest_mrt.django_testcase import MRTTestCase
class TestRemovePhone(MRTTestCase):
db_url = "sqlite:///test.db"
migrate_from = ("myapp", "0009_add_phone")
migrate_to = ("myapp", "0010_remove_phone")
def test_rollback_is_safe(self):
self.assertRollbackSafe()
def test_existing_rows_survive(self):
User = self.old_apps.get_model("myapp", "User")
User.objects.create(name="Alice", phone="+1-555-0100")
self.assertDataIntact()
- assertRollbackSafe(): full pytest-mrt check (seed + upgrade + downgrade
+ schema/data integrity verification)
- assertDataIntact(): user-seeded data check after manual setup
- old_apps / apps: historical Django app registry at migrate_from / migrate_to
- setUpClass migrates to migrate_from; tearDownClass rolls back to zero
- setUp restores migrate_from state before each test method
- assertDataIntact now snapshots pre-existing PKs before SmartSeeder runs, then verifies user-created rows survived rollback (not just seeder rows) - add try/except recovery in assertDataIntact: on downgrade failure, downgrade_app_zero is called so the next test starts from a clean state - _historical_apps changed from @staticmethod to @classmethod and reads cls.db_alias (default "default") instead of hardcoding connections["default"] - add db_alias class attribute to MRTTestCase for multi-DB projects - guard MRTTestCase import in __init__.py with try/except ImportError so non-Django users are never affected by future django_testcase dependencies - add two new unit tests: recovery path and user-row-loss detection
|
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
- use redundant alias pattern (as X) for re-exports in __init__.py - fix import sort order in django_testcase.py (sqlalchemy before local) - remove unused `connect_calls` variable in test - remove unused SmartSeeder imports in test functions
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
MRTTestCase(unittest.TestCase)— drop-in base class for Django teams not using pytestassertRollbackSafe()delegates toDjangoRollbackVerifier(full seed+upgrade+downgrade+verify cycle)assertDataIntact()verifies both user-created rows AND SmartSeeder rows survive rollbackold_apps/appsproperties expose historical Django app registries for each migration stateBug fixes in this PR
assertDataIntactonly checked SmartSeeder rows, not user ORM datadowngrade()raised mid-testtry/except→downgrade_app_zerofallback, then re-raise_historical_appshardcodedconnections["default"]@classmethodreadscls.db_alias(default:"default"); override for multi-DB__init__.pyimportedMRTTestCaseunconditionallytry/except ImportError— safe for non-Django usersTest plan
tests/test_django_testcase.py— all mocked, no real DB requiredtest_assert_data_intact_recovery_on_downgrade_failure— verifiesdowngrade_app_zerois calledtest_assert_data_intact_detects_user_row_loss— verifies pre-existing rows are trackedUsage