测试django模式和数据迁移,包括排序
项目描述
django-test-migrations
功能
- 允许测试
django
模式和数据处理迁移 - 允许测试正向和回滚迁移
- 允许测试迁移顺序
- 允许测试迁移名称
- 允许测试数据库配置
- 完全使用注解类型化,并使用
mypy
检查,与PEP561兼容 - 易于开始:拥有大量文档、测试和教程
安装
pip install django-test-migrations
我们支持几个django
版本
3.2
4.1
4.2
5.0
其他版本可能也可以正常工作,但它们不受官方支持。
测试Django迁移
在django
领域,测试迁移并不常见。但有时这是完全必要的。何时?
当我们进行复杂的模式或数据更改,并确保现有数据不会被损坏时。我们可能还希望确保所有迁移都可以安全回滚。最后,我们希望确保迁移顺序正确,并且具有正确的依赖关系。
测试正向迁移
为了测试所有迁移,我们有一个Migrator
类。
它有三个方法可以操作
-
.apply_initial_migration()
接受应用和迁移名称,在实际迁移发生之前生成一个状态。它通过应用所有传递的参数及之前的迁移来创建before state
。 -
.apply_tested_migration()
接受应用和迁移名称来执行实际迁移 -
.reset()
在测试完成后清理一切
所以,这里有一个例子
from django_test_migrations.migrator import Migrator
migrator = Migrator(database='default')
# Initial migration, currently our model has only a single string field:
# Note:
# We are testing migration `0002_someitem_is_clean`, so we are specifying
# the name of the previous migration (`0001_initial`) in the
# .apply_initial_migration() method in order to prepare a state of the database
# before applying the migration we are going to test.
#
old_state = migrator.apply_initial_migration(('main_app', '0001_initial'))
SomeItem = old_state.apps.get_model('main_app', 'SomeItem')
# Let's create a model with just a single field specified:
SomeItem.objects.create(string_field='a')
assert len(SomeItem._meta.get_fields()) == 2 # id + string_field
# Now this migration will add `is_clean` field to the model:
new_state = migrator.apply_tested_migration(
('main_app', '0002_someitem_is_clean'),
)
SomeItem = new_state.apps.get_model('main_app', 'SomeItem')
# We can now test how our migration worked, new field is there:
assert SomeItem.objects.filter(is_clean=True).count() == 0
assert len(SomeItem._meta.get_fields()) == 3 # id + string_field + is_clean
# Cleanup:
migrator.reset()
这是一个正向迁移的例子。
逆向迁移
事实上,你也可以测试逆向迁移。除了传递的迁移名称和你的逻辑外,没有什么真正改变。
migrator = Migrator()
# Currently our model has two field, but we need a rollback:
old_state = migrator.apply_initial_migration(
('main_app', '0002_someitem_is_clean'),
)
SomeItem = old_state.apps.get_model('main_app', 'SomeItem')
# Create some data to illustrate your cases:
# ...
# Now this migration will drop `is_clean` field:
new_state = migrator.apply_tested_migration(('main_app', '0001_initial'))
# Assert the results:
# ...
# Cleanup:
migrator.reset()
测试迁移顺序
有时我们还想确保我们的迁移顺序正确,并且所有我们的dependencies = [...]
都是正确的。
为了实现这一点,我们有一个plan.py
模块。
这是它的用法
from django_test_migrations.plan import all_migrations, nodes_to_tuples
main_migrations = all_migrations('default', ['main_app', 'other_app'])
assert nodes_to_tuples(main_migrations) == [
('main_app', '0001_initial'),
('main_app', '0002_someitem_is_clean'),
('other_app', '0001_initial'),
('main_app', '0003_update_is_clean'),
('main_app', '0004_auto_20191119_2125'),
('other_app', '0002_auto_20191120_2230'),
]
这样你就可以确保迁移和相互依赖的应用将按正确的顺序执行。
factory_boy
集成
如果你使用工厂创建模型,你可以用factory
的方法替换它们各自的.build()
或.create()
调用,并将模型名称和工厂类作为参数传递
import factory
old_state = migrator.apply_initial_migration(
('main_app', '0002_someitem_is_clean'),
)
SomeItem = old_state.apps.get_model('main_app', 'SomeItem')
# instead of
# item = SomeItemFactory.create()
# use this:
factory.create(SomeItem, FACTORY_CLASS=SomeItemFactory)
# ...
测试框架集成 🐍
我们支持几个测试框架作为一等公民。毕竟,这是一个测试工具!
请注意,在测试开始时,Django post_migrate
信号的接收者列表被清除,之后恢复。如果你需要测试自己的post_migrate
信号,则在测试期间附加/删除它们。
pytest
我们提供的django-test-migrations
附带一个pytest
插件,它提供了两个方便的固定装置
migrator_factory
为你提供了创建任何数据库的Migrator
类的机会migrator
实例为'default'
数据库
这是它的用法
import pytest
@pytest.mark.django_db
def test_pytest_plugin_initial(migrator):
"""Ensures that the initial migration works."""
old_state = migrator.apply_initial_migration(('main_app', None))
with pytest.raises(LookupError):
# Model does not yet exist:
old_state.apps.get_model('main_app', 'SomeItem')
new_state = migrator.apply_tested_migration(('main_app', '0001_initial'))
# After the initial migration is done, we can use the model state:
SomeItem = new_state.apps.get_model('main_app', 'SomeItem')
assert SomeItem.objects.filter(string_field='').count() == 0
unittest
我们还提供与内置的unittest
框架的集成。
这是它的用法
from django_test_migrations.contrib.unittest_case import MigratorTestCase
class TestDirectMigration(MigratorTestCase):
"""This class is used to test direct migrations."""
migrate_from = ('main_app', '0002_someitem_is_clean')
migrate_to = ('main_app', '0003_update_is_clean')
def prepare(self):
"""Prepare some data before the migration."""
SomeItem = self.old_state.apps.get_model('main_app', 'SomeItem')
SomeItem.objects.create(string_field='a')
SomeItem.objects.create(string_field='a b')
def test_migration_main0003(self):
"""Run the test itself."""
SomeItem = self.new_state.apps.get_model('main_app', 'SomeItem')
assert SomeItem.objects.count() == 2
assert SomeItem.objects.filter(is_clean=True).count() == 1
仅选择迁移测试
在CI系统中,获得即时反馈很重要。运行应用数据库迁移的测试可能会减慢测试执行速度,因此通常在并行运行较慢的迁移测试的同时运行标准的、快速的常规单元测试是一个好主意。
pytest
django_test_migrations
给每个使用migrator_factory
或migrator
固定装置的测试添加了migration_test
标记。要仅运行迁移测试,使用-m
选项
pytest -m migration_test # Runs only migration tests
pytest -m "not migration_test" # Runs all except migration tests
unittest
django_test_migrations
给每个MigratorTestCase
子类添加了migration_test
标记。要仅运行迁移测试,使用--tag
选项
python mange.py test --tag=migration_test # Runs only migration tests
python mange.py test --exclude-tag=migration_test # Runs all except migration tests
Django Checks
django_test_migrations
带有两组 Django 检查,用于
- 自动检测迁移脚本生成的名称
- 验证数据库设置的一部分
测试迁移名称
django
在您运行 makemigrations
时为您生成迁移名称。这些名称不好(了解更多为什么它不好!)(阅读更多关于为什么它不好!): 0004_auto_20191119_2125.py
这个迁移做了什么?它有哪些更改?
也可以在创建迁移时传递 --name
属性,但很容易忘记。
我们提供了一个自动解决方案:生成错误并针对每个名称不正确的迁移进行检查的 django
检查。
将我们的检查添加到您的 INSTALLED_APPS
INSTALLED_APPS = [
# ...
# Our custom check:
'django_test_migrations.contrib.django_checks.AutoNames',
]
然后在您的 CI 中运行
python manage.py check --deploy
这样,您就可以避免迁移中的错误名称。
您有无法重命名的迁移吗?将它们添加到忽略列表
# settings.py
DTM_IGNORED_MIGRATIONS = {
('main_app', '0004_auto_20191119_2125'),
('dependency_app', '0001_auto_20201110_2100'),
}
然后我们不会抱怨它们。
或者您可以选择完全忽略整个应用程序
# settings.py
DTM_IGNORED_MIGRATIONS = {
('dependency_app', '*'),
('another_dependency_app', '*'),
}
数据库配置
将我们的检查添加到 INSTALLED_APPS
INSTALLED_APPS = [
# ...
# Our custom check:
'django_test_migrations.contrib.django_checks.DatabaseConfiguration',
]
然后只需在您的 CI 中运行 check
管理命令,如上所述。
相关项目
您可能还喜欢
- django-migration-linter - 检测 django 项目的向后不兼容迁移。
- wemake-django-template - 针对代码质量和安全性的 bleeding edge django 模板,集成了
django-test-migrations
和django-migration-linter
。
致谢
本项目基于其他优秀人士的工作
许可证
MIT。
项目详情
下载文件
为您的平台下载文件。如果您不确定选择哪个,请了解更多关于 安装包 的信息。
源代码分布
构建分布
散列 对于 django_test_migrations-1.4.0-py3-none-any.whl
算法 | 散列摘要 | |
---|---|---|
SHA256 | 294dff98f6d43d020d4046b971bac5339e7c71458a35e9ad6450c388fe16ed6b |
|
MD5 | c146a866a8c68b3dc869b60b6c22c765 |
|
BLAKE2b-256 | 546011c792485df2cc242bb13ab167dcd3cc1ff1d943bcb235b8320dd71c6bf6 |