【问题标题】:How to unittest that a django model method called with unittest.mock?如何对使用 unittest.mock 调用的 django 模型方法进行单元测试?
【发布时间】:2013-06-03 00:29:13
【问题描述】:

我很难理解如何使用 unittest.mock 库。
我有这个模型:

from django.db import models

class Data(models.Model):
    field1 = models.CharField(max_length=50)
    field2 = models.CharField(max_length=50)
    // ... more fields

    _PASSWORD_KEY = 'some_random_password_key'
    _password = models.CharField(max_length=255, db_column='password')

    def _set_password(self, raw_password):
        """
        Encode raw_password and save as self._password
        """
        // do some Vigenère magic

    def _get_password(self):
        """
        Decode encrypted password with _PASSWORD_KEY and return the original.
        """
        return raw_password

    password = property(_get_password, _set_password)

我想测试当我执行data = Data(password='password') 时会调用_set_password
我手动确认它被调用了,但是这个单元测试失败了(我从 unittest.mock 文档的例子中得到):

from mock import patch
from someapp.models import Data

def test_set_password_is_called(self):
    with patch.object(Data, '_set_password') as password_method:
        data = Data(password='password123')

    password_method.assert_called_once_with('password123')

带有此消息:

Failure
Traceback (most recent call last):
  File "/Users/walkman/project/someapp/tests.py", line 75, in test_set_password_is_called
    password_method.assert_called_once_with('password123')
  File "/usr/local/lib/python2.7/site-packages/mock.py", line 845, in assert_called_once_with
    raise AssertionError(msg)
AssertionError: Expected to be called once. Called 0 times.

我做错了什么?

【问题讨论】:

  • 模拟文档有一个example for mocking properties 使用PropertyMock。也许这会有所帮助?
  • with patch('tracker.models.PlayingHistoryAudit._set_password', new_callable=PropertyMock) as mock_password: 也不能解决问题:(
  • 请注意,该示例并未模拟 setter,而是模拟属性本身,即 patch('tracker.models.PlayingHistoryAudit.password', ..) ... hmm,但刚刚意识到可能不适合检查 setter 是否被调用。
  • 没错!我想检查二传手是否正确地完成了它的工作。也许检查它的方法是在赋值后查找 _password 属性。
  • 更改测试并确定设置器(即 _set_password)通过测试值是否符合您的期望来执行您期望的操作可能是最简单的。

标签: python unit-testing python-mock


【解决方案1】:

因为密码是一个属性,并且属性类 getter 和 setter 上的属性在调用堆栈中使用,所以您最终不会调用类上的修补属性。您可以更改测试,类似于此处所述

http://www.voidspace.org.uk/python/weblog/arch_d7_2011_06_04.shtml

请注意这是有效的

class Test(object):

def test(self):
    return self.test2()


def test2(self):
    print("This was Called")

和测试

with patch.object(Test, 'test2') as mock_method:
    d = Test()
    d.test()

mock_method.assert_called()

【讨论】:

  • 老实说,我不知道你在说什么。什么是“属性类 getter 和 setter 上的属性在调用堆栈中使用,您最终不会调用类上的修补属性”是什么意思?如果为属性设置值,则在这种情况下将调用 setter 方法_set_password。我的问题是,我的测试是错误的,没有检测到这一点。
  • 由于您将密码定义为属性,因此您的类在设置和获取值时调用定义的方法。除了调用不是您期望的那样,而是使用属性类中的预定义方法。你可以改变你的测试,直接调用你的方法。由于 unittest.patch 期望直接调用该方法。
  • 所以在设置密码属性时,这不是我认为的工作方式?
  • 不,它完全符合您的想法(或多或少)。问题是它不能像你认为的那样在幕后工作,它应该与补丁一起工作才能以你想要的方式进行测试。
猜你喜欢
  • 1970-01-01
  • 2018-05-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多