5

python中是否有任何等效的严格模拟?一些报告意外调用模拟方法的机制(本示例中的 action.step2() ),就像 GoogleMock 框架中的这样。

class Action:
    def step1(self, arg):
        return False

    def step2(self, arg):
        return False

def algorithm(action):
    action.step1('111')
    action.step2('222')
    return True

class TestAlgorithm(unittest.TestCase):
    def test_algorithm(self):
        actionMock = mock.create_autospec(Action)
        self.assertTrue(algorithm(actionMock))
        actionMock.step1.assert_called_once_with('111')
4

3 回答 3

5

看起来它不支持开箱即用。然而,至少有两种方法可以达到相同的结果。

通过允许成员名单

根据模拟文档

spec:这可以是字符串列表,也可以是充当模拟对象规范的现有对象(类或实例)。如果您传入一个对象,则通过在该对象上调用 dir 来形成一个字符串列表(不包括不受支持的魔法属性和方法)。访问不在此列表中的任何属性都会引发 AttributeError

因此,为了使您的测试示例失败,只需替换

actionMock = mock.create_autospec(Action)

actionMock = mock.Mock(spec=['step1'])

与将类或实例作为参数传递相比,这种方法具有某些缺点spec,因为您必须传递所有允许的方法,而不是对它们设置期望,从而有效地注册它们两次。此外,如果您需要限制方法的子集,则必须传递除这些方法之外的所有方法的列表。这可以通过以下方式实现:

all_members = dir(Action)  # according to docs this is what's happening behind the scenes
all_members.remove('step2')  # remove all unwanted methods 
actionMock = mock.Mock(spec=all_members)

在受限方法上设置例外

另一种方法是在您不想被调用的方法上明确设置失败:

def test_algorithm(self):
    actionMock = mock.create_autospec(Action)
    actionMock.step2.side_effect = AttributeError("Called step2") # <<< like this
    self.assertTrue(algorithm(actionMock))
    actionMock.step1.assert_called_once_with('111')

这也有一些限制:您必须设置错误和期望。

最后一点,解决问题的一个根本方法是修补mock以向构造函数添加strict参数Mock并发送拉取请求。要么它会被接受,要么mock维护者会指出如何实现这一点。:)

于 2014-07-09T06:37:40.793 回答
0

是的,这可以使用spec=andautospec=参数实现。有关更多信息,请参阅有关 Autospeccing 的模拟文档。在您的示例中,它将变为:

action_mock = mock.Mock(spec=Action)

或者:

action_mock = mock.Mock('Action', autospec=True)
于 2014-07-08T13:36:16.333 回答
0

另一种可能:

在受限方法上单独检查 call_count

确保call_count不应调用的方法为零。

class TestAlgorithm(unittest.TestCase):
    def test_algorithm(self):
        actionMock = mock.create_autospec(Action)
        self.assertTrue(algorithm(actionMock))
        actionMock.step1.assert_called_once_with('111')
        self.assertEqual(actionMock.step2.call_count, 0) # <<< like this

缺点是您必须一一检查所有意外呼叫。

于 2014-07-10T21:18:59.757 回答