How do I run tests against a Django data migration?
using the following example from the documentation。P></
1 2 3 4 5 6 7 8 9 10 11 12 13 | def combine_names(apps, schema_editor): Person = apps.get_model("yourappname","Person") for person in Person.objects.all(): person.name ="%s %s" % (person.first_name, person.last_name) person.save() class Migration(migrations.Migration): dependencies = [ ('yourappname', '0001_initial'), ] operations = [ migrations.RunPython(combine_names), ] |
如何创建和运行所有的测试,这对confirming is the),migrated日期正确吗?P></
在实际应用之前,通过一些基本单元测试来运行数据迁移功能(例如来自OP的
乍一看,这不应该比普通的Django单元测试困难得多:迁移是Python模块,
第一个困难是由于默认迁移文件名以数字开头。例如,假设op(即django)数据迁移示例中的代码位于
1 | from yourappname.migrations.0002_my_data_migration import combine_names |
号
但这会引发一个
至少有两种方法可以实现这一点:
重命名迁移文件,使其不以数字开头。根据文档,这应该是完全正确的:"Django只关心每个迁移有不同的名称。"然后您可以像上面那样使用
如果您想坚持使用默认编号的迁移文件名,可以使用python的
第二个困难来自这样一个事实:您的数据迁移函数被设计为被传递到
现在,我不确定这是否适用于每一个案例(请任何人,如果你能澄清的话,请发表评论),但是对于我们的案例,从django.apps导入
下面是一个简化的示例,展示了如何为OP示例实现这一点,假设迁移文件名为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | from importlib import import_module from django.test import TestCase from django.apps import apps from django.db import connection from yourappname.models import Person # Our filename starts with a number, so we use import_module data_migration = import_module('yourappname.migrations.0002_my_data_migration') class DataMigrationTests(TestCase): def __init__(self, *args, **kwargs): super(DataMigrationTests, self).__init__(*args, **kwargs) # Some test values self.first_name = 'John' self.last_name = 'Doe' def test_combine_names(self): # Create a dummy Person Person.objects.create(first_name=self.first_name, last_name=self.last_name, name=None) # Run the data migration function data_migration.combine_names(apps, connection.schema_editor()) # Test the result person = Person.objects.get(id=1) self.assertEqual('{} {}'.format(self.first_name, self.last_name), person.name) |
我在谷歌上做了一些工作来解决同一个问题,找到了一篇为我钉钉子的文章,看起来不像现有答案那么简单。所以,把这个放在这里,以防它能帮助其他人。
Django's
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | from django.apps import apps from django.test import TestCase from django.db.migrations.executor import MigrationExecutor from django.db import connection class TestMigrations(TestCase): @property def app(self): return apps.get_containing_app_config(type(self).__module__).name migrate_from = None migrate_to = None def setUp(self): assert self.migrate_from and self.migrate_to, \ "TestCase '{}' must define migrate_from and migrate_to properties".format(type(self).__name__) self.migrate_from = [(self.app, self.migrate_from)] self.migrate_to = [(self.app, self.migrate_to)] executor = MigrationExecutor(connection) old_apps = executor.loader.project_state(self.migrate_from).apps # Reverse to the original migration executor.migrate(self.migrate_from) self.setUpBeforeMigration(old_apps) # Run the migration to test executor = MigrationExecutor(connection) executor.loader.build_graph() # reload. executor.migrate(self.migrate_to) self.apps = executor.loader.project_state(self.migrate_to).apps def setUpBeforeMigration(self, apps): pass |
。
他们提出的一个示例用例是:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | class TagsTestCase(TestMigrations): migrate_from = '0009_previous_migration' migrate_to = '0010_migration_being_tested' def setUpBeforeMigration(self, apps): BlogPost = apps.get_model('blog', 'Post') self.post_id = BlogPost.objects.create( title ="A test post with tags", body ="", tags ="tag1 tag2", ).id def test_tags_migrated(self): BlogPost = self.apps.get_model('blog', 'Post') post = BlogPost.objects.get(id=self.post_id) self.assertEqual(post.tags.count(), 2) self.assertEqual(post.tags.all()[0].name,"tag1") self.assertEqual(post.tags.all()[1].name,"tag2") |
您可以在先前的迁移中添加一个粗略的if语句,用于测试测试套件是否正在运行,如果正在运行,则添加初始数据——这样,您就可以编写一个测试来检查对象是否处于您希望它们处于的最终状态。只需确保您的条件与生产兼容,下面是一个可以与
1 2 3 | import sys if 'test in sys.argv: # do steps to update your operations |
对于更"完整"的解决方案,这篇较旧的博客文章有一些好的信息和更多关于灵感的最新评论:
https://micknelson.wordpress.com/2013/03/01/testing-django-migrations/评论