From 24b050c1552fe9c27f04552a8f1799ff40ef125c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Skar=C5=BCy=C5=84ski?= Date: Sun, 4 Oct 2020 14:48:35 +0200 Subject: [PATCH 1/5] mark unittest test case subclasses with django tag --- django_test_migrations/constants.py | 4 ++++ django_test_migrations/contrib/unittest_case.py | 4 +++- setup.cfg | 1 + .../test_contrib/test_unittest_case/test_unittest_case.py | 7 +++++++ 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 django_test_migrations/constants.py diff --git a/django_test_migrations/constants.py b/django_test_migrations/constants.py new file mode 100644 index 0000000..2d8bae4 --- /dev/null +++ b/django_test_migrations/constants.py @@ -0,0 +1,4 @@ +from typing_extensions import Final + +#: marker/tag indicating that marked test is Django's migrations test +MIGRATION_TEST_MARKER: Final = 'migration_test' diff --git a/django_test_migrations/contrib/unittest_case.py b/django_test_migrations/contrib/unittest_case.py index 20ed8b4..b12c219 100644 --- a/django_test_migrations/contrib/unittest_case.py +++ b/django_test_migrations/contrib/unittest_case.py @@ -2,12 +2,14 @@ from django.db.migrations.state import ProjectState from django.db.models.signals import post_migrate, pre_migrate -from django.test import TransactionTestCase +from django.test import TransactionTestCase, tag +from django_test_migrations.constants import MIGRATION_TEST_MARKER from django_test_migrations.migrator import Migrator from django_test_migrations.types import MigrationSpec +@tag(MIGRATION_TEST_MARKER) class MigratorTestCase(TransactionTestCase): """Used when using raw ``unitest`` library for test.""" diff --git a/setup.cfg b/setup.cfg index 2add252..c102d42 100644 --- a/setup.cfg +++ b/setup.cfg @@ -98,6 +98,7 @@ branch = True # And we completely test it anyway. omit = django_test_migrations/contrib/pytest_plugin.py + django_test_migrations/constants.py [coverage:report] skip_covered = True diff --git a/tests/test_contrib/test_unittest_case/test_unittest_case.py b/tests/test_contrib/test_unittest_case/test_unittest_case.py index b0b3688..f83457a 100644 --- a/tests/test_contrib/test_unittest_case/test_unittest_case.py +++ b/tests/test_contrib/test_unittest_case/test_unittest_case.py @@ -1,3 +1,4 @@ +from django_test_migrations.constants import MIGRATION_TEST_MARKER from django_test_migrations.contrib.unittest_case import MigratorTestCase @@ -38,3 +39,9 @@ def test_migration_main0001(self): SomeItem = self.new_state.apps.get_model('main_app', 'SomeItem') assert SomeItem.objects.count() == 2 + + +def test_migration_test_marker_tag(): + """Ensure ``MigratorTestCase`` sublasses are properly tagged.""" + assert MIGRATION_TEST_MARKER in TestDirectMigration.tags + assert MIGRATION_TEST_MARKER in TestBackwardMigration.tags From bb1f2fdd8bb30ac5992d0e6f366de0fa3165ba0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Skar=C5=BCy=C5=84ski?= Date: Sun, 4 Oct 2020 14:49:11 +0200 Subject: [PATCH 2/5] mark pytest tests using migrator_fixture with proper mark --- .../contrib/pytest_plugin.py | 24 ++++++++++ .../test_pytest_plugin/test_plugin.py | 44 +++++++++++++++++++ 2 files changed, 68 insertions(+) diff --git a/django_test_migrations/contrib/pytest_plugin.py b/django_test_migrations/contrib/pytest_plugin.py index 3856d07..c0bf287 100644 --- a/django_test_migrations/contrib/pytest_plugin.py +++ b/django_test_migrations/contrib/pytest_plugin.py @@ -4,6 +4,30 @@ from django.db import DEFAULT_DB_ALIAS from django.db.models.signals import post_migrate, pre_migrate +from django_test_migrations.constants import MIGRATION_TEST_MARKER + + +def pytest_load_initial_conftests(early_config): + """Register pytest's markers.""" + early_config.addinivalue_line( + 'markers', + "{0}: mark the test as a Django's migration test.".format( + MIGRATION_TEST_MARKER, + ), + ) + + +def pytest_collection_modifyitems(session, items): # noqa: WPS110 + """Mark all tests using ``migrator_factory`` fixture with proper marks. + + Add ``MIGRATION_TEST_MARKER`` marker to all items using + ``migrator_factory`` fixture. + + """ + for pytest_item in items: + if 'migrator_factory' in getattr(pytest_item, 'fixturenames', []): + pytest_item.add_marker(MIGRATION_TEST_MARKER) + @pytest.fixture() def migrator_factory(request, transactional_db, django_db_use_migrations): diff --git a/tests/test_contrib/test_pytest_plugin/test_plugin.py b/tests/test_contrib/test_pytest_plugin/test_plugin.py index 6f3f9cb..0b63692 100644 --- a/tests/test_contrib/test_pytest_plugin/test_plugin.py +++ b/tests/test_contrib/test_pytest_plugin/test_plugin.py @@ -1,5 +1,8 @@ +import re import subprocess +from django_test_migrations.constants import MIGRATION_TEST_MARKER + def test_call_pytest_setup_plan(): """Checks that module is registered and visible in the meta data.""" @@ -19,3 +22,44 @@ def test_call_pytest_setup_plan(): assert 'migrator' in output_text assert 'migrator_factory' in output_text + + +def test_pytest_registers_marker(): + """Ensure ``MIGRATION_TEST_MARKER`` marker is registered.""" + output_text = subprocess.check_output( + ['pytest', '--markers'], + stderr=subprocess.STDOUT, + universal_newlines=True, + encoding='utf8', + ) + + assert MIGRATION_TEST_MARKER in output_text + + +def test_pytest_markers(): + """Ensure ``MIGRATION_TEST_MARKER`` markers are properly added.""" + output_text = subprocess.check_output( + [ + 'pytest', + '--collect-only', + + # Collect only tests marked with ``MIGRATION_TEST_MARKER`` marker + '-m', + MIGRATION_TEST_MARKER, + + # We need this part because otherwise check fails with `1` code: + '--cov-fail-under', + '0', + ], + stderr=subprocess.STDOUT, + universal_newlines=True, + encoding='utf8', + ) + + search_result = re.search( + r'(?P\d+)\s+selected', + output_text, + ) + assert search_result + assert int(search_result.group('selected_number') or 0) > 0 + assert 'test_pytest_plugin' in output_text From 0230b47a3e1207f7d9ec6cd0945d7b35ace9022c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Skar=C5=BCy=C5=84ski?= Date: Sun, 4 Oct 2020 14:58:30 +0200 Subject: [PATCH 3/5] add info about migration tests markers/tags --- README.md | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/README.md b/README.md index 60b5fa6..ff43f26 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,34 @@ class TestDirectMigration(MigratorTestCase): assert SomeItem.objects.filter(is_clean=True).count() == 1 ``` +### Choosing only migrations tests + +In CI systems it is important to get instant feedback. Running tests that +apply database migration can slow down tests execution, so it is often a good +idea to run standard, fast, regular unit tests without migrations in parallel +with slower migrations tests. + +#### pytest + +`django_test_migrations` adds `migration_test` marker to each test using +`migrator_factory` or `migrator` fixture. +To run only migrations test, use `-m` option: + +```bash +pytest -m migration_test +``` + +#### unittest + +`django_test_migrations` adds `migration_test` +[tag](https://docs.djangoproject.com/en/3.0/topics/testing/tools/#tagging-tests) +to every `MigratorTestCase` subclass. +To run only migrations tests, use `--tag` option: + +```bash +python mange.py test --tag=migration_test +``` + ## Django Checks From 413a236e6120d51e8a94439df7d496e967f9b8c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Skar=C5=BCy=C5=84ski?= Date: Sun, 4 Oct 2020 15:11:02 +0200 Subject: [PATCH 4/5] fix typo in constants.py --- django_test_migrations/constants.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/django_test_migrations/constants.py b/django_test_migrations/constants.py index 2d8bae4..4ffd687 100644 --- a/django_test_migrations/constants.py +++ b/django_test_migrations/constants.py @@ -1,4 +1,4 @@ from typing_extensions import Final -#: marker/tag indicating that marked test is Django's migrations test +#: marker/tag indicating that marked test is a Django's migration test MIGRATION_TEST_MARKER: Final = 'migration_test' From b9b6fb4a5aca59c6216a6eff1297960116e5c4c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Skar=C5=BCy=C5=84ski?= Date: Mon, 5 Oct 2020 08:55:45 +0200 Subject: [PATCH 5/5] add example how to exclude migration tests --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ff43f26..1958013 100644 --- a/README.md +++ b/README.md @@ -235,7 +235,8 @@ with slower migrations tests. To run only migrations test, use `-m` option: ```bash -pytest -m migration_test +pytest -m migration_test # runs only migraion tests +pytest -m "not migration_test" # runs all except migraion tests ``` #### unittest @@ -246,7 +247,8 @@ to every `MigratorTestCase` subclass. To run only migrations tests, use `--tag` option: ```bash -python mange.py test --tag=migration_test +python mange.py test --tag=migration_test # runs only migraion tests +python mange.py test --exclude-tag=migration_test # runs all except migraion tests ```