测试在单元测试中是否在另一个函数内调用函数

时间:2015-02-12 09:29:15

标签: python unit-testing mocking

python中的mock和patch新手。我有一个有方法更新的课程

class myclass(object):
   def update(self, name, passwd):
       self.update_in(name,passwd)
   def update_in(self, name, passwd):
       self.name = name
       self.passwd = passwd

现在在另一个类中,我必须测试更新方法并确定update方法调用update_in方法。我如何实现这一目标?

2 个答案:

答案 0 :(得分:2)

通过unittest.mock模块中的patch,您可以修补生产代码的方法,函数,对象或属性。现在我在myclass中假设mymodule,我将向您展示如何进行测试的简单方法。

from unittest.mock import patch
from mymodule import myclass

m = myclass()
with patch("mymodule.myclass.update_in", autospec=True) as mock_update_in:
    m.update('me', 'mypassword')
    mock_update_in.assert_called_with('me', 'mypassword')

@patch("mymodule.myclass.update_in", autospec=True)
def my_test(mock_update_in):
    m = myclass()
    m.update('me', 'mypassword')
    mock_update_in.assert_called_with('me', 'mypassword')

my_test()

现在,您可以使用patch代替patch.object(myclass, "update_in", autospec=True),并在测试模块中修补myclass的引用。我的感觉是在你不能做的时候使用patch.object:你必须确保你正在修补你的测试所调用的代码,而不是其他东西。例如,您mymodule_b使用了from mymodule import myclass,现在您在mymodule_b中测试方法,如:

from mymodule import myclass
def get_registered(username, password):
    m = myclass()
    m.update(username, password)
    return m

现在,myclass 使用的get_registered()引用不是测试模块中的引用。下一个测试将失败

from mymodule import myclass
from mymodule_b import get_registered

with patch.object(myclass, "update_in", autospec=True) as mock_update_in:
    m = get_registered('me', 'mypassword')
    assert m is not None
    mock_update_in.assert_called_with('me', 'mypassword')

在开始使用patch函数之前,最好先查看Where to patch会话。

关于使用autospec=True的说明:autospecpatch函数系列的一个真正强大的选项,您的修补对象将从原始引用中获取签名和属性并阻止某些测试中的愚蠢错误。要了解autospec的价值,请查看下一个示例:

m = myclass()
with patch("mymodule.myclass.update_in") as mock_update_in:
    m.update('me', 'mypassword')
    mock_update_in.assert_call_with('you', 'yourpassword')

之前的测试通过,即使您使用错误的参数进行检查只是因为mock_update_in是标准MagicMock(),因为您要求的每个属性都会返回MagicMock个对象或者您调用的每种方法都不会引发任何异常:在该方案中,mock_update_in.assert_call_with('you', 'yourpassword')将返回MagicMock()

答案 1 :(得分:1)

您应该使用mock.patch将方法替换为模拟,然后您可以在调用update方法后声明有关模拟的各种内容。

patcher = mock.patch.object(myclass, 'update_in')
patched = patcher.start()

m=myclass()
m.update('foo', 'bar')

assert patched.call_count == 1
patched.assert_called_with('foo', 'bar')