Running Tests¶
You have two primary options for running the configured set of tests:
Automatically at the command-line via
--test-alembic
Pytest Alembic
automatically adds a flag,pytest --test-alembic
, which will automatically invoke the baked-in tests.This can be convenient if you want to exclude migrations tests most of the time, but include them for e.g. CI. By default,
pytest tests
would then, not run migrations tests.Additionally, it means you don’t need to manually include the tests in a test file somewhere in your project.
If your tests dont generally reside at/below a
tests/
directory with atests/conftest.py
file, you can/should set thepytest_alembic_tests_path
option, described below.You can directly import the tests you want to include at any point in your project.
from pytest_alembic.tests import ( test_model_definitions_match_ddl, test_single_head_revision, test_up_down_consistency, test_upgrade, )
This can be convenient if you always want the migrations tests to run, or else want a reference to the tests’ existence somewhere in your source code. Pytest would automatically include the tests every time you run i.e.
pytest tests
.
In either case, you can exclude migrations tests using pytest’s “marker” system, i.e.
pytest -m "not alembic"
.
Configuration¶
Pytest Config¶
In any of the pytest config locations (pytest.ini
, setup.cfg
, pyproject.toml
),
you can set any of the following configuration options to alter global pytest-alembic
behavior.
pytest_alembic_include
List of built-in tests to include. If specified, ‘pytest_alembic_exclude’ is ignored. If both are omitted, all tests are included. The tests should be listed as a comma delimited string containing the tests’ names.
pytest_alembic_exclude
List of built-in tests to exclude. Ignored if ‘pytest_alembic_include’ is specified. The tests should be listed as a comma delimited string containing the tests’ names.
pytest_alembic_tests_folder
The location under which the built-in tests will be bound. This defaults to ‘tests/’ (the tests themselves then being executed from tests/pytest_alembic/), the typical test location. However this can be customized if pytest is, for example, invoked from a parent directory like
pytest folder/tests
, or the tests are otherwise located at a different location, relative to thepytest
invocation.Note
As of pytest-alembic version 0.8.5, this option is ignored. Instead, if you require customizing the registration location, you should use
pytest_alembic_tests_path
instead.pytest_alembic_tests_path
Note
Introduced in v0.10.1.
The location at which the built-in tests will be bound. This defaults to ‘tests/conftest.py’. Typically, you would want this to coincide with the path at which your alembic_engine is being defined/registered. Note that this path must be the full path, relative to the root location at which pytest is being invoked.
This option has replaced
pytest_alembic_tests_folder
due to changes in how pytest test collection needed to be performed in around pytest ~7.0.Additionally, this option is only required if you are using the
--test-alembic
flag.
Alembic Config¶
See the Config fixture for more detail.
Alternative to --test-alembic
¶
There is some magic to the automatic inclusion of the built-in tests. It’s not obvious, from looking at any of the test code, that these tests (sometimes) magically be included.
Also, one may want to include the built-in tests automatically, every time, without needing to
specify --test-alembic
, or by doing so conditionally in-code.
Whatever the reason, it is possible to simply import the test implementations from
pytest_alembic
directly.
Simply import the tests at whatever location you want tests to be included:
from pytest_alembic.tests import test_single_head_revision
from pytest_alembic.tests import test_upgrade
from pytest_alembic.tests import test_model_definitions_match_ddl
from pytest_alembic.tests import test_up_down_consistency
Furthermore, doing this as well as using --test-alembic
will cause the tests to be
run twice (since they’d be considered unique tests with different paths). So generally, these
methods should be considered mutually exclusive.
Multiple Alembic Histories¶
It may be the case that you have the histories for two separate databases (or schemas) in a single project. How should you structure your tests?
This is likely one of the times you want to avoid the use of the --test-alembic
flag and the automatic insertion of tests.
Instead, you’ll likely want to want to make use of create_alembic_fixture()
.
from pytest_alembic import tests, create_alembic_fixture
# The argument here represents the equivalent to `alembic_config`. Depending
# on your setup, this may be configuring the "file" argument, "script_location",
# or some other way of configuring one or the other of your histories.
history_1 = create_alembic_fixture({"file": "alembic.ini"})
def test_single_head_revision_history_1(history_1):
tests.test_single_head_revision(history_1)
def test_upgrade_history_1(history_1):
tests.test_upgrade(history_1)
def test_model_definitions_match_ddl_history_1(history_1):
tests.test_model_definitions_match_ddl(history_1)
def test_up_down_consistency_history_1(history_1):
tests.test_up_down_consistency(history_1)
# The 2nd fixture, and the 2nd set of tests.
history_2 = create_alembic_fixture({"file": "history_2.ini"})
def test_single_head_revision_history_2(history_2):
tests.test_single_head_revision(history_2)
def test_upgrade_history_2(history_2):
tests.test_upgrade(history_2)
def test_model_definitions_match_ddl_history_2(history_2):
tests.test_model_definitions_match_ddl(history_2)
def test_up_down_consistency_history_2(history_2):
tests.test_up_down_consistency(history_2)
Due to limitations of how pytest test collection occurs, there’s currently no obvious way to automatically set up and define these tests to occur against different fixtures.
Pytest Marks¶
Pytest-alembic automatically marks all tests which use the alembic_runner
fixture
(including all built-in tests) with the alembic
mark.
This means you can optionally include/exclude migrations tests using the vanilla pytest mark machinery like so:
pytest -m 'alembic' # Run *only* alembic tests
pytest -m 'not alembic' # Run everything *except* alembic tests