使用 side_efffect 模拟 class 属性

Mock class attribute with side_efffect

如何在访问模拟对象的属性时引发异常?

我尝试对以下代码段执行相同的操作,

import unittest
from unittest import TestCase
from django.core.exceptions import ObjectDoesNotExist
from unittest.mock import MagicMock, PropertyMock


def function_to_call_one_to_one(model_instance):
    try:
        return model_instance.artist.name
    except ObjectDoesNotExist:
        # calling `model_instance.artist` will raise `ObjectDoesNotExist` exception
        return "raised `ObjectDoesNotExist`"


class TestObjectDoesNotExist(TestCase):
    def test_artist_name(self):
        model_instance = MagicMock()
        model_instance.artist.name = "Michael Jackson"
        name = function_to_call_one_to_one(model_instance)
        self.assertEqual(name, "Michael Jackson")

    def test_artist_name_with_error(self):
        model_instance = MagicMock()
        model_instance.artist = PropertyMock(side_effect=ObjectDoesNotExist)
        res = function_to_call_one_to_one(model_instance)
        self.assertEqual(res, "raised `ObjectDoesNotExist`")


if __name__ == '__main__':
    unittest.main()

不幸的是,测试函数 test_artist_name_with_error(...) 失败并显示消息

AssertionError: <MagicMock name='mock.artist.name' id='140084482479440'> != 'raised ObjectDoesNotExist'

如何为这种情况编写单元测试?

注意: 我看过这个 SO post,Python: Mock side_effect on object attribute,但是,它对我不起作用。我希望这个例子是 可重现的

好问题。以下是您可能忽略的 docs 的一部分:

Because of the way mock attributes are stored you can’t directly attach a PropertyMock to a mock object. Instead, you can attach it to the mock type object.

这个有效:

type(model_instance).artist = PropertyMock(side_effect=ObjectDoesNotExist)