测试抽象模型-Django 2.2.4/sqlite3 2.6.0 [英] Testing abstract models - django 2.2.4 / sqlite3 2.6.0

查看:51
本文介绍了测试抽象模型-Django 2.2.4/sqlite3 2.6.0的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试使用django 2.2.4/sqlite3 2.6.0/python 3.6.8测试一些简单的抽象mixins.

I'm trying to test some simple abstract mixins using django 2.2.4/sqlite3 2.6.0/python 3.6.8.

目前,我在使用架构编辑器从测试数据库中删除模型时遇到问题.

Currently I'm having issues deleting a model from the test database using the schema editor.

我有以下测试案例:

from django.test import TestCase
from django.db.models.base import ModelBase
from django.db import connection


class ModelMixinTestCase(TestCase):
    """
    Test Case for abstract mixin models.
    """
    mixin = None
    model = None

    @classmethod
    def setUpClass(cls) -> None:
        # Create a real model from the mixin
        cls.model = ModelBase(
            "__Test" + cls.mixin.__name__,
            (cls.mixin,),
            {'__module__': cls.mixin.__module__}
        )

        # Use schema_editor to create schema
        with connection.schema_editor() as editor:
            editor.create_model(cls.model)

        super().setUpClass()

    @classmethod
    def tearDownClass(cls) -> None:
        # Use schema_editor to delete schema
        with connection.schema_editor() as editor:
            editor.delete_model(cls.model)

        super().tearDownClass()

可以这样使用:

class MyMixinTestCase(ModelMixinTestCase):
    mixin = MyMixin

    def test_true(self):
        self.assertTrue(True)

这确实允许创建和测试模型.问题在于,在 ModelMixinTestCase.tearDownClass 中, connection.schema_editor()无法禁用在 django.db.backends.sqlite3.base中完成的约束检查.使用:

This does allow for a model to be created and tested. The problem is that within ModelMixinTestCase.tearDownClass, connection.schema_editor() is unable to disable constraint checking which is done in django.db.backends.sqlite3.base using:

    def disable_constraint_checking(self):
        with self.cursor() as cursor:
            cursor.execute('PRAGMA foreign_keys = OFF')
            # Foreign key constraints cannot be turned off while in a multi-
            # statement transaction. Fetch the current state of the pragma
            # to determine if constraints are effectively disabled.
            enabled = cursor.execute('PRAGMA foreign_keys').fetchone()[0]
        return not bool(enabled)

这会导致 django.db.backends.sqlite3.schema 中的 DatabaseSchemaEditor __ enter __ 中出现异常:

this leads to an exception in __enter__ of the DatabaseSchemaEditor in django.db.backends.sqlite3.schema:

    def __enter__(self):
        # Some SQLite schema alterations need foreign key constraints to be
        # disabled. Enforce it here for the duration of the schema edition.
        if not self.connection.disable_constraint_checking():
            raise NotSupportedError(
                'SQLite schema editor cannot be used while foreign key '
                'constraint checks are enabled. Make sure to disable them '
                'before entering a transaction.atomic() context because '
                'SQLite does not support disabling them in the middle of '
                'a multi-statement transaction.'
            )
        return super().__enter__()

因此,基于所有这些,我假设我们处于原子上下文中,但是我目前不知道退出该上下文并删除模型的最干净方法是什么.

So based on all this I'm assuming we are in an atomic context but I'm currently not sure what the cleanest way is to exit that context and delete the model.

推荐答案

简单解决方案

因此,在进行一些挖掘和测试之后,最好让Django的 TestCase 正常关闭事务,然后从测试数据库中删除模型.本质上,我们只是先调用 super().tearDownClass()而不是最后一个.

Simple Solution

So after a little digging and testing it seems that it's best to let django's TestCase close the transaction normally and then remove the model from the test database. Essentially we just call the super().tearDownClass() first instead of last.

由于这是一个有用的课程,我将发布完整的课程,供其他人复制/粘贴.

Since it's a useful class I'll post the full class for others to copy/paste.

class ModelMixinTestCase(TestCase):
    """
    Test Case for abstract mixin models.
    Subclass and set cls.mixin to your desired mixin.
    access your model using cls.model.
    """
    mixin = None
    model = None

    @classmethod
    def setUpClass(cls) -> None:
        # Create a real model from the mixin
        cls.model = ModelBase(
            "__Test" + cls.mixin.__name__,
            (cls.mixin,),
            {'__module__': cls.mixin.__module__}
        )

        # Use schema_editor to create schema
        with connection.schema_editor() as editor:
            editor.create_model(cls.model)

        super().setUpClass()

    @classmethod
    def tearDownClass(cls) -> None:
        # allow the transaction to exit
        super().tearDownClass()

        # Use schema_editor to delete schema
        with connection.schema_editor() as editor:
            editor.delete_model(cls.model)

        # close the connection
        connection.close()

示例用法1

class MyMixinTestCase(ModelMixinTestCase):
    mixin = MyMixin

    def test_true(self):
        self.assertTrue(True)

示例用法2

class SortableModelMixinTestCase(ModelMixinTestCase):
    mixin = SortableModelMixin

    def setUp(self) -> None:
        self.objects = [self.model.objects.create(pk=i) for i in range(10)]

    def test_order_linear(self) -> None:
        i = 1
        for item in self.objects:
            self.assertEqual(i, item.sortable_order)
            i += 1

这篇关于测试抽象模型-Django 2.2.4/sqlite3 2.6.0的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆