测试中的模型 - Django 1.7 问题

15 投票
2 回答
1772 浏览
提问于 2025-04-19 20:22

我正在尝试把我的项目迁移到Django 1.7版本。除了一个问题,其他都很顺利。就是测试文件夹里的模型。

Django 1.7的新迁移系统会自动运行迁移命令。之前是通过syncdb来处理的。这意味着如果一个模型没有包含在迁移中,它就不会被添加到数据库里(测试数据库也是如此)。这正是我现在遇到的情况。

我做的事情是:

在我的/app/tests/models.py文件里,我有一个简单的模型:class TestBaseImage(BaseImage): pass。这个模型的作用就是继承一个抽象BaseImage模型。

然后在测试中,我创建这个简单模型的实例来进行测试。

问题是,这种方法不再有效。因为这个模型没有包含在迁移中(这很明显,因为我不想把测试模型放到生产数据库里)。运行我的测试时会出现数据库错误,提示表不存在。这很合理,因为它确实没有包含在迁移中。

有没有什么办法可以让它在新的迁移系统下正常工作?我找不到“修复”的方法。

我使用的代码:

app/tests/models.py

from ..models import BaseImage


class TestBaseImage(BaseImage):
    """Dummy model just to test BaseImage abstract class"""
    pass

app/models.py

class BaseImage(models.Model):
    # ... fields ...
    class Meta:
        abstract = True

工厂:

class BaseImageFactory(factory.django.DjangoModelFactory):
    """Factory class for Vessel model"""
    FACTORY_FOR = BaseImage
    ABSTRACT_FACTORY = True


class PortImageFactory(BaseImageFactory):
    FACTORY_FOR = PortImage

示例测试:

def get_model_field(model, field_name):
    """Returns field instance"""
    return model._meta.get_field_by_name(field_name)[0]


def test_owner_field(self):
    """Tests owner field"""
    field = get_model_field(BaseImage, "owner")

    self.assertIsInstance(field, models.ForeignKey)
    self.assertEqual(field.rel.to, get_user_model())

2 个回答

3

这里有一个看起来有效的解决办法。就是让迁移框架误以为你的应用没有迁移。在 settings.py 文件中,你可以这样做:

if 'test' in sys.argv:
    # Only during unittests...

    # myapp uses a test-only model, which won't be loaded if we only load
    # our real migration files, so point to a nonexistent one, which will make
    # the test runner fall back to 'syncdb' behavior.
    MIGRATION_MODULES = {
        'myapp': 'myapp.migrations_not_used_in_tests'
    }

我在 Django开发者邮件列表的第一篇帖子上找到了这个主意,现在它也在 Django的代码中使用,不过在未来的Django版本中,可能不再适用,因为那时候迁移是必须的,而“syncdb回退”功能会被移除。

5

这里有一个请求,希望能找到一种只用于测试的模型的方法,详细信息可以在这里查看。

作为一种解决办法,你可以把你的tests.py文件拆分出来,单独做成一个应用。

tests
|--migrations
|--__init__.py
|--models.py
|--tests.py

最后你会得到类似这样的结构:

myapp
|-migrations
|-tests
|--migrations
|--__init__.py
|--models.py
|--tests.py
|-__init__.py
|-models.py
|-views.py

然后你需要把它添加到你的 INSTALLED_APPS 中。

INSTALLED_APPS = (
    # ...
    'myapp',
    'myapp.tests',
)

你可能不想在生产环境中安装 myapp.tests,所以可以保持不同的设置文件。可以这样做:

INSTALLED_APPS = (
    # ...
    'myapp',
)

try:
    from local_settings import *
except ImportError:
    pass

或者更好的是,创建一个测试运行器,把你的测试放在那里。

最后但同样重要的是,记得运行 python manage.py makemigrations

撰写回答