[英]How to mock python dict __str__ method?
我有一个方法,它将需要包含某些条目的字典作为参数。 例如,我可能期望字典中有一个type
键,其值需要是['typeA', 'typeB', 'typeC']
。 如果缺少键,我SpecFormatException
该方法抛出异常SpecFormatException
。 异常消息应该读取类似'type' entry is missing in spec dict: {'foo': 'bar', 'baz': [1, 2, 3]}
。
我正在编写一个测试来验证是否使用正确的错误消息抛出异常,但由于dict.__str__()
方法的输出是不确定的,我的测试是不稳定的。 我想,如果我可以修补dict.__str__()
方法以输出类似“是的,我是你的字典”之类的东西,那么我可以修复片状,但是当我尝试用以下方法修补我的测试时:
import mock
import my_verifier
@mock.patch('my_verifier.dict')
def testErrorMessage(this, dict_str):
dict_str.return_value = 'YES I AM YOUR DICTIONARY'
...
尝试运行我的测试时收到错误消息“my_verifier.py 没有属性‘dict’”。
我认为嘲笑__str__
方法是这里的正确方法,但我到底该怎么做?
您对错误消息的测试需要具体到什么程度? 您能否仅断言您期望的某些部分在那里,例如:
import pytest
def test_my_method_error_message():
offending_key = 'test'
data = {offending_key: 'whatever'}
with pytest.raises(SpecFormatException) as excinfo:
my_method(data)
assert data in str(excinfo.value)
显然,您可能还需要测试消息的其他部分。 测试 EXACT 字符串可能是您想要做的,也可能不是,因为该消息可能会改变。 如果您需要沿着这条路线走下去,我建议可能将字符串(或字符串模板)存储在任何东西都可以访问的地方,以便您的测试可以根据类变量或配置参数进行断言。
如果使用自定义 dict2str 函数替换内置dict.__str__
方法是一种选择,那么这里有一个按字母顺序对键进行排序的方法:
def det_str(x):
if isinstance(x, dict):
return '{{{}}}'.format(', '.join('{!r}: {}'.format(k, det_str(v)) for k, v in sorted(x.items())))
else:
return str(x)
>>> det_str({'a': 1, 'b': 0, 'c': -1})
"{'a': 1, 'b': 0, 'c': -1}"
>>> det_str({'c': -1, 'a': 1, 'b': 0})
"{'a': 1, 'b': 0, 'c': -1}"
也递归地工作:
>>> det_str({'b': 0, 'a': 1, 'c': -1, 'd': {'z': 10, 'x': 20, 'y': -30}})
"{'a': 1, 'b': 0, 'c': -1, 'd': {'x': 20, 'y': -30, 'z': 10}}"
我将假设您在引发异常时将字典作为参数传递,例如
d = {'foo': 'bar', 'baz': [1, 2, 3]}
if not d.get('type') in ['typeA', 'typeB', 'typeC']:
raise SpecFormatException(d)
第一个测试将只关注异常本身,这意味着参数并不重要,只要它具有__str__
方法:
def testExceptionMessage(self):
d = mock.MagicMock()
exc = SpecFormatException(d)
observed = str(exc)
self.assertEqual(observed,
"'type' entry is missing in spec dict: {}".format(d)
如果你检查的值d.__str__.called
前和调用后str(exc)
,你应该能看到价值变动False
到True
,验证SpecFormatException
确实使用参数的__str__
方法创造的价值observed
。
第二个测试侧重于按预期引发的异常。 你真的不需要检查它的消息是什么,因为 1) 你已经在别处测试过了 2) 消息并不真正包含任何你无法从dict
实例本身收集的信息以及事实SpecFormatException
确实被引发了。
def testRaiseException(self):
with self.assertRaises(SpecFormatException):
# code that should cause SpecFormatException be raised
这是一个较旧的问题,但我遇到了同样的困难,找不到有效的答案。 我最终使用unittest.mock.MagicMock
来模拟对象函数的__str__
输出。 MagicMock
旨在模拟 Python 的魔法函数,例如__str__
。
您不需要为测试本身使用任何类似SpecFormatException
东西。 您可以使用mock.patch
作为上下文管理器——对于您的代码,这看起来像:
import my_verifier
import unittest.mock
def test_my_method_error_message():
with mock.patch("my_verifier.dict", mock.MagicMock()) as mock_dict:
mock_dict.__str__.return_value = "YES I AM YOUR DICTIONARY"
assert str(mock_dict) == "YES I AM YOUR DICTIONARY"
# ...other tests that rely on a mocked instance of my_verifier.dict...
# ...other tests that don't rely on a mocked instance of my_verifier.dict...
假设my_verifier
有一个dict
对象/方法,这允许您控制打印my_verifier.dict
用于一个或多个测试的输出,但无需用模拟对象完全替换my_verifier.dict
。
您还可以在同一上下文中模拟my_verifier.dict
其他(魔术)函数, my_verifier.dict
任何其他测试驻留在上下文之外。
patch.object方法也可能有用。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.