Django: Best way to unit-test an abstract model

后端 未结 13 1353
一个人的身影
一个人的身影 2020-12-24 12:28

I need to write some unit tests for an abstract base model, that provides some basic functionality that should be used by other apps. It it would be necessary to define a mo

13条回答
  •  温柔的废话
    2020-12-24 13:18

    In Django 2.2, if you only have one abstract class to test, you can use the following:

    from django.db import connection
    from django.db import models
    from django.db.models.base import ModelBase
    from django.db.utils import ProgrammingError
    from django.test import TestCase
    
    from yourapp.models import Base  # Base here is the abstract model.
    
    
    class BaseModelTest(TestCase):
        @classmethod
        def setUpClass(cls):
            # Create dummy model extending Base, a mixin, if we haven't already.
            if not hasattr(cls, '_base_model'):
                cls._base_model = ModelBase(
                    'Base',
                    ( Base, ),
                    { '__module__': Base.__module__ }
                )
    
                # Create the schema for our base model. If a schema is already
                # create then let's not create another one.
                try:
                    with connection.schema_editor() as schema_editor:
                        schema_editor.create_model(cls._base_model)
                    super(BaseModelTest, cls).setUpClass()
                except ProgrammingError:
                    # NOTE: We get a ProgrammingError since that is what
                    #       is being thrown by Postgres. If we were using
                    #       MySQL, then we should catch OperationalError
                    #       exceptions.
                    pass
    
                cls._test_base = cls._base_model.objects.create()
    
        @classmethod
        def tearDownClass(cls):
            try:
                with connection.schema_editor() as schema_editor:
                    schema_editor.delete_model(cls._base_model)
                super(BaseModelTest, cls).tearDownClass()
            except ProgrammingError:
                # NOTE: We get a ProgrammingError since that is what
                #       is being thrown by Postgres. If we were using
                #       MySQL, then we should catch OperationalError
                #       exceptions.
                pass
    

    This answer is only a tweaking of DSynergy's answer. One notable difference is that we are using setUpClass() instead of setUpTestData(). This difference is important since using the latter will result in InterfaceError (when using PostgreSQL) or the equivalent in other databases when the other test cases are run. As to the reason why this happens, I do not know at the time of writing.

    NOTE: If you have more than one abstract class to test, it is better to use the other solutions.

提交回复
热议问题