这是我想要测试的函数:
def send_something():
conn = lib.conn.SSH1
conn.open()
conn.send('lsn')
if 'home' not in conn.recbuf:
return lib.FAIL
conn.send('whoamin')
if USER not in conn.recbuf:
return lib.FAIL
return lib.PASS
每次我调用 conn.send(( 时,调用的输出都存储在 conn.recbuf 中。为了测试这一点,我需要每次调用conn.recbuf时都不同。(我知道我可以将conn.recbuf更改为包含home和USER的字符串,但这不适用于更复杂的函数(
以下是我到目前为止在测试中得出的结论:
@mock.patch.object(demo_sequence.lib, 'conn')
def test_send_something(mock_conn):
mock_conn.SSH1.recbuf = 'home'
assert demo_sequence.lib.PASS == demo_sequence.send_something()
mock_conn.SSH1.send.assert_any_call('lsn')
mock_conn.SSH1.send.assert_any_call('whoamin')
显然,这失败了,因为conn.recbuf只是"家",不包含USER。
我需要类似 conn.recbuf.side_effect = ['home', USER] 的东西,但在只引用 recbuf 而不调用它时会起作用。
如果您能够将 conn.recbuf 更改为属性,则可以使用 PropertyMock 来实现所需的效果。
from unittest import mock
class Dummy:
def __init__(self, myattribute):
self._myattribute = myattribute
@property
def myattribute(self):
return self._myattribute
def test():
with mock.patch('__main__.Dummy.myattribute', new_callable=mock.PropertyMock) as mocked_attribute:
mocked_attribute.side_effect = [4,5,6]
d = Dummy("foo")
print(d.myattribute)
print(d.myattribute)
print(d.myattribute)
但是,对于您的实际问题,我认为对您的问题的评论似乎包括合理的方法。
您要查找的是side_effect
:https://docs.python.org/3/library/unittest.mock.html
假设mock
是您的模拟对象。然后你可以这样做:
mock.side_effect = [a,b,c]
然后每次调用 mock
时,都会返回列表中的下一个值。
mock() # -> a
mock() # -> b
mock() # -> c
我之前曾遇到过类似的问题,并使用PropertyMock
找到了解决方案。在我的例子中,我想在测试用例中的其他地方存储一个值,以便在我模拟的类上设置属性时通过side_effect
调用方法来断言。
我认为它也应该适用于您的情况(如果我了解您要做什么(。
解决方案是为您的财产recbuf
使用PropertyMock
,并将side_effect
放在那里:
from unittest.mock import MagicMock, PropertyMock
conn = MagicMock()
type(conn).recbuf = PropertyMock(side_effect=['home', USER])
每当访问属性recbuf
时,都会调用副作用,在这种情况下,每次都会循环访问['home', USER]
。我想您还需要修补该USER
值,以免出现名称错误。
希望这有效/有帮助!