Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/293.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/unit-testing/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
模拟在方法调用后更改实例变量的python类?_Python_Unit Testing_Mocking - Fatal编程技术网

模拟在方法调用后更改实例变量的python类?

模拟在方法调用后更改实例变量的python类?,python,unit-testing,mocking,Python,Unit Testing,Mocking,我有一些代码,其中调用方法update()会更改一些实例变量的值。我使用更改后的值来留下一个循环。下面是我的代码的简化示例: def do_stuff(self): # get a new instance of A a = get_a() while True: a.update() if a.state == 'state': break 这是该类的一个简单版本(我无法更改该类,因为它是第三方库): 现在我想通

我有一些代码,其中调用方法
update()
会更改一些实例变量的值。我使用更改后的值来留下一个循环。下面是我的代码的简化示例:

def do_stuff(self):
    # get a new instance of A
    a = get_a()
    while True:
        a.update()
        if a.state == 'state':
            break
这是该类的一个简单版本(我无法更改该类,因为它是第三方库):

现在我想通过模拟类A来测试我的函数
do_stuff()
。要测试函数的每个方面,我想拥有
state
的所有不同值,并且它应该在每次调用
A.update()
(迭代不同的状态)后改变

我开始为我的单元测试设置:

from mock import Mock, patch
import unittest

class TestClass(unittest.TestClass):

    @patch('get_a')
    def test_do_stuff(self, mock_get_a):
         mock_a = Mock(spec=A)
         mock_get_a.return_value = mock_a

         # do some assertions
我可以用
Mock
实现这种行为吗? 我知道
Mock
副作用
为连续函数调用返回不同的值。但我想不出在函数调用后更改实例变量值的方法?

设置:

from mock import Mock, MagicMock, patch

sep = '***********************\n'

# non-mock mocks
def get_a():
    return A()
def extern_func():
    return 'foo'

def do_stuff(self):
    # get a new instance of A
    a = get_a()
    while True:
        a.update()
        print a.state
        if a.state == 'state':
            break

class A(object):
    def __init__(self):
        self.state = ''

    def update(self):
        # call to external system
        self.state = extern_func()
正如@Simeon Viser所提到的,模仿
extern_func
可以:
side\u effect
可以是一个函数,您可以使用
auto\u spec=True
参数模拟unbound方法
a.update
。 使用上下文管理器: 使用装饰器:
警告:我从未编写过全面的单元测试,只是最近才开始阅读模拟文档,所以尽管我似乎已经完成了这项工作,但我不能评论它在您的测试方案中的有效性。欢迎编辑。

是否可以保持原样并模拟外部功能?这似乎是迭代状态的最简单方法,因为您确实可以使用
副作用
让它返回每个状态。@SimeonVisser:您的建议是可能的,但与建议背道而驰。它不与建议背道而驰;事实上,它跟随它,因为您需要在使用对象的位置修补对象。这只会根据导入
external_func
的方式而变化(但在您的示例中我们看不到这一点)。如果是
import mymodule
mymodule.external_func()
,则需要更改修补程序以包括
mymodule
。如@simeonviser的注释中所述,您的解决方案违反了建议。但到目前为止,这似乎是唯一可能的解决办法。我会试着让我的测试运行,并让你知道我的发现。。。。这不是一个建议,它描述了如何引用正在修补的对象-您必须遵循这些说明。在我的示例中,正在修补的对象和测试/模拟代码位于同一个模块中。
from mock import Mock, MagicMock, patch

sep = '***********************\n'

# non-mock mocks
def get_a():
    return A()
def extern_func():
    return 'foo'

def do_stuff(self):
    # get a new instance of A
    a = get_a()
    while True:
        a.update()
        print a.state
        if a.state == 'state':
            break

class A(object):
    def __init__(self):
        self.state = ''

    def update(self):
        # call to external system
        self.state = extern_func()
print sep, 'patch extern'
mock = MagicMock(side_effect = [1,2,3,4, 'state'])
@patch('__main__.extern_func', mock)
def foo():
    do_stuff(3)
foo()

>>> 
***********************
patch extern
1
2
3
4
state
print sep, 'patch update context manager call do_stuff'
def update_mock(self):
    self.state = mock()
mock = MagicMock(side_effect = [1,2,3,4, 'state'])
with patch.object(A, 'update', autospec = True) as mock_update:
    mock_update.side_effect = update_mock
    do_stuff(3)

>>>
***********************
patch update context manager call do_stuff
1
2
3
4
state
print sep, 'patch update decorator test_do_stuff'
def update_mock(self):
    self.state = mock()
mock = MagicMock(side_effect = [1,2,3,4, 'state'])
@patch.object(A, 'update', autospec = True, side_effect = update_mock)
def test_do_stuff(self):
    do_stuff(3)
test_do_stuff()

>>>
***********************
patch update decorator test_do_stuff
1
2
3
4
state