【问题标题】:Correct way to unit test Django models without transaction errors在没有事务错误的情况下单元测试 Django 模型的正确方法
【发布时间】:2012-12-22 20:30:26
【问题描述】:

我正在编写一些带有 unique=Trueblank=Falsenull=False 等约束的模型。我正在尝试为带有鼻子的模型编写测试。但是,如果我编写这样的测试:

from job_sites.models import Site, SiteType

@raises(IntegrityError)
def test_empty_site():
   s = Site()
   s.save()

@raises(IntegrityError)
def test_empty_site_type():
   st = SiteType()
   st.save()

我得到一个这样的 DatabaseError: DatabaseError: current transaction is aborted, commands ignored until end of transaction block 运行第一次测试后。

当我预计会出现错误时,运行 DJango 模型测试的正确方法是什么?

作为参考,模型如下所示:

class SiteType(models.Model):
    site_type_id = models.AutoField(primary_key=True)
    site_type = models.CharField(max_length=32, unique=True, blank=False, null=False, default=None)
    site_type_abbrev = models.CharField(max_length=32, blank=True)

    class Meta:
        db_table = u'site_types'

class Site(models.Model):
    site_id = models.AutoField(primary_key=True, blank=False, null=False, db_index=True)
    site_name = models.CharField(max_length=128, blank=False, null=False, db_index=True)
    site_type = models.ForeignKey(SiteType, blank=True, null=True)
    date_entered = models.DateTimeField(auto_now_add=True)

    class Meta:
        db_table = u'sites'

我的约束和默认值如下所示:

ALTER TABLE site_types ADD CONSTRAINT site_types_site_type_name_minlen CHECK (char_length(site_type) > 0);
ALTER TABLE sites ALTER COLUMN date_entered SET DEFAULT now();
ALTER TABLE sites ADD CONSTRAINT sites_site_name_minlen CHECK (char_length(site_name) > 0);

【问题讨论】:

    标签: django nose django-testing


    【解决方案1】:

    您应该将测试创建为 Django 的 TestCase 的子类,而不是使用鼻子的简洁测试定义。这样,您的数据库等将在运行时为您设置和配置,所有事务都将得到神奇的处理。

    关于如何为 Django 项目编写测试的概述:https://docs.djangoproject.com/en/dev/topics/testing/overview/

    您尝试执行的操作类似于:

    from django.db import IntegrityError
    from django.utils import unittest
    from job_sites.models import Site, SiteType
    
    class TestMyStuff(unittest.TestCase):
    
        def test_empty_site(self):
            s = Site()
            assertRaises(IntegrityError, s.save())
    
        def test_empty_site_type(self):
            st = SiteType()
            assertRaises(IntegrityError, st.save())
    

    (免责声明:我没有实际运行此代码,因此它可能无法正常工作。)

    但是,测试这种东西可能是浪费时间。此处测试的唯一逻辑是 Django 内部的,因此您不会通过测试来了解您的应用程序的任何内容。

    【讨论】:

    • 我会试试这个。但是,测试这个并不是浪费时间,因为我的约束是在数据库级别实现的,我需要知道数据库模式对于我的应用程序是正确的。通过这种方式,我在自动生成的代码中发现了几个错误。
    • 您发布的那种测试不适用于 PostgreSQL 数据库。在抛出第一个 IntegrityError 之后,下一次尝试调用 save() 会导致与我原来的问题相同的 DatabaseError 。必须有一些公认的方式来使用 postgres 进行单元测试。
    • 我可以看看你的模型定义吗?当您说“约束是在数据库级别实现的”时,我不确定您的意思。您是连接到预先存在的数据库还是什么?
    猜你喜欢
    • 2023-01-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多