繁体   English   中英

如何模拟 python dict __str__ 方法?

[英]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) ,你应该能看到价值变动FalseTrue ,验证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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM