【问题标题】:Is there a standard way to mock Django models?有模拟 Django 模型的标准方法吗?
【发布时间】:2018-03-31 18:01:12
【问题描述】:

我有一个模型叫Pdb

class Pdb(models.Model):

    id = models.TextField(primary_key=True)
    title = models.TextField()

与模型Residue是一对多的关系:

class Residue(models.Model):

    id = models.TextField(primary_key=True)
    name = models.TextField()
    pdb = models.ForeignKey(Pdb)

单元测试Pdb 很好:

def test_can_create_pdb(self):
    pdb = Pdb(pk="1XXY", title="The PDB Title")
    pdb.save()
    self.assertEqual(Pdb.objects.all().count(), 1)
    retrieved_pdb = Pdb.objects.first()
    self.assertEqual(retrieved_pdb, pdb)

当我对Residue 进行单元测试时,我只想使用一个模拟 Pdb 对象:

def test_can_create_residue(self):
    pdb = Mock(Pdb)
    residue = Residue(pk="1RRRA1", name="VAL", pdb=mock_pdb)
    residue.save()

但这失败了,因为它需要一些名为_state的属性:

AttributeError: Mock object has no attribute '_state'

所以我不断添加模拟属性使其看起来像一个真实的模型,但最终我得到了:

django.db.utils.ConnectionDoesNotExist: The connection db doesn't exist

我不知道如何模拟对数据库的实际调用。有没有标准的方法来做到这一点?我真的不想在测试数据库中实际创建 Pdb 记录,因为那样测试就不会被隔离。

是否有既定的最佳实践方法来做到这一点?

我获得的大部分 SF 和 google 结果都与模拟模型的特定方法有关。任何帮助将不胜感激。

【问题讨论】:

    标签: django unit-testing django-models orm tdd


    【解决方案1】:

    您在这里不是严格的单元测试,因为您涉及到数据库,我称之为集成测试,但这是另一个非常激烈的争论!

    我的建议是让你的包装测试类继承自 django.test.TestCase。如果您担心每个单独的测试用例被完全隔离,那么您可以创建多个类,每个类都有一个测试方法。

    这些测试是否需要编写也值得重新考虑,因为它们似乎只是在验证框架是否正常工作。

    【讨论】:

    • 我绝对同意您关于仅测试框架是否正常工作的观点 - 它非常接近。我对这些测试的理由是我正在测试正确的字段是否存在并且字段类型是否正确,尽管我猜这与测试常量非常接近。已经从 Django TestCase 继承的测试,我只是从上面的 sn-p 中省略了它。不过谢谢!
    • 就个人而言,我会将该测试留给更广泛的集成测试。编写涵盖微小细节的单元测试很容易陷入困境。我试着把它们想象成一个黑盒子,入口点是公共使用的 API。
    【解决方案2】:

    哦,我设法用一个名为“mixer”的库解决了这个问题......

    from mixer.backend.django import mixer
    
    def test_can_create_residue(self):
        mock_pdb = mixer.blend(Pdb)
        residue = Residue(pk="1RRRA1", name="VAL", pdb=mock_pdb)
        residue.save()
    

    仍然认为 django 应该提供一种本地方式来做到这一点。它已经提供了很多测试工具——这感觉像是正确单元测试的主要部分。

    【讨论】:

      【解决方案3】:

      我不确定你所说的模拟 Django 模型到底是什么意思。编写需要一些模型对象的测试的最简单选择是使用test fixture。它基本上是一个 YAML 文件,会在您的测试运行之前加载到数据库表中。

      您在your answer 中提到了mixer,它看起来像是一个用于随机生成这些测试夹具的库。

      这些都是很好的工具,但它们仍然需要访问数据库,而且它们比纯单元测试慢得多。如果您想完全模拟数据库访问,请尝试Django mock queries。它完全模拟了数据库访问层,因此速度非常快,而且您不必担心外键。当我想测试一些具有简单数据库访问权限的复杂代码时,我会使用它。如果数据库访问有一些复杂的查询条件,那我还是选择真实的数据库吧。

      全面披露:我是 Django 模拟查询项目的次要贡献者。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2013-11-19
        • 1970-01-01
        • 2015-02-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-01-12
        • 1970-01-01
        相关资源
        最近更新 更多