在Python 2.7中,如何正确地模拟一个访问时引发异常的可下标属性?

8 投票
1 回答
14195 浏览
提问于 2025-04-18 01:24

我在使用Python 2.7.1和mock 1.0.1,想写一个单元测试,目的是要能成功抛出一个IndexError错误。当我尝试用类似下面的方式访问一个模拟属性时:

repo = MagicMock()
repo.heads = PropertyMock(side_effect=IndexError())
with self.assertRaises(IndexError):
    _ = repo.heads['nonexistant']

那么,最符合Python风格的做法是什么呢?上面的代码根本没有抛出IndexError,而是抛出了一个TypeError,提示说PropertyMock不能被下标访问。

TypeError: 'PropertyMock' object is not subscriptable

我需要说明的是,实际的单元测试根本不是这样的。真实的单元测试是想验证某种行为,但如果不模拟一个第三方模块中的类,就无法做到这一点。也就是说,我需要在调用Repo对象的getitem时,模拟出这个模块的行为,从而抛出IndexError。

撇开上下文不谈,我是不是有点多余?我先把repo声明为一个MagicMock()对象,然后又把repo.heads声明为一个PropertyMock对象。为了这个问题我研究了很久mock的文档,但没有找到这个特定用例的例子,我也无法让它正常工作。我还尝试过使用MagicMock(side_effect=IndexError()),但也没有成功。

我觉得应该可以简单地在模拟中实现这个行为,然后继续我的工作。我相信这是可能的,只是我不知道怎么做,所以我才在这里提问。

那么,真正的解决方案是什么呢?

1 个回答

11

你可以用 MagicMock 来替代 PropertyMock,这样在 repo.heads 的时候就可以正常工作了。不过我不确定你的实际测试是否依赖于 PropertyMock

repo = MagicMock()
repo.heads.__getitem__.side_effect = IndexError
with self.assertRaises(IndexError):
    _ = repo.heads['nonexistant']

如果你希望在访问特定值时抛出 IndexError 错误,你需要给 repo.heads.__getitem__.side_effect 赋值一个自定义的处理函数。

撰写回答