如何模拟 Django 模型对象(及其方法)?

Posted

技术标签:

【中文标题】如何模拟 Django 模型对象(及其方法)?【英文标题】:How to mock a Django model object (along with its methods)? 【发布时间】:2018-01-12 17:50:28 【问题描述】:

我试图在下面的虚拟方法中模拟一个链接的 Django 模型对象,

# utils.py
def foo_something_exist():
   if Foo.objects.get(a='something').exist():
      return 'exist'



# test.py
import unittest.mock import patch

import utils

.
.
.
@patch('utils.Foo')
def test_foo_something_exist_returns_none(self, mock_foo):
   mock_foo.objects.get.exists.return_value = False
   self.assertIsNone(utils.foo_something_exist()) 
.
.
.

test_foo_something_exist() 未通过测试。我发现utils.py中的Foo.objects.get(a='something').exist()是一个MagicMock对象(<MagicMock name='Member.objects.get().exists()' id='xxxxxx'>)而不是False,这导致了这个测试函数的失败。是的,我也试过mock_foo.objects.return_value.get.return_value.exists.return_value = False,在帖子中提到过。用于正确模拟模型对象(及其链式方法)的指针/提示非常感谢。

提前谢谢你。

【问题讨论】:

【参考方案1】:

不要修补模型本身,而是要对 model.objects 进行修补,然后模拟链的每个部分:

@patch('utils.Foo.objects')
def test_foo_something_exist_returns_none(self, mock_foo):
    # just to show how to do it with longer chains
    # mock_foo.filter.return_value = mock_foo
    # mock_foo.exclude.return_value = mock_foo            
    mock_foo.get.return_value = mock_foo
    mock_foo.exists.return_value = False

    self.assertIsNone(utils.foo_something_exist()) 

这也适用于.filter().exclude() 和其他模型操作。我还发现Model Mommy 在测试 Django 模型时非常有用。

【讨论】:

感谢您的回答。我可以知道mock_foo.get.return_value = mock_foo 是做什么的吗? 它使用修补的对象作为每个链接方法调用的返回值。因此,您最终会得到一个具有方法的修补对象,并且它们都返回相同的修补对象。这样,链接方法调用的顺序也无关紧要。

以上是关于如何模拟 Django 模型对象(及其方法)?的主要内容,如果未能解决你的问题,请参考以下文章

如何从现有模型生成与之配合的数据

在 Django 中模拟模型字段验证器

人工神经网络模型及其性能

如何模拟 Laravel Eloquent 模型的静态方法?

Django内置函数详解Httprequest详解(模拟搜索/模拟用户登陆/模拟上传文件功能)

模拟 django 设置:AttributeError:“设置”对象没有属性“FOO”