Python 如何正确模拟类的私有成员
我正试图为依赖于另一个私有方法的方法编写一些单元测试。-如下例所示:Python 如何正确模拟类的私有成员,python,python-3.x,python-unittest,Python,Python 3.x,Python Unittest,我正试图为依赖于另一个私有方法的方法编写一些单元测试。-如下例所示: def is_member_of(self, group_name): members = self.__get_group_members(group_name) 我想模拟的私有方法是\uu get\u group\u members;我还想模拟私有属性\uuuuu user\u id,因为它将在函数的is\u member\u中使用(上面的示例中未显示) 到目前为止,我所拥有的: import unittest fr
def is_member_of(self, group_name):
members = self.__get_group_members(group_name)
我想模拟的私有方法是\uu get\u group\u members
;我还想模拟私有属性\uuuuu user\u id
,因为它将在函数的is\u member\u中使用(上面的示例中未显示)
到目前为止,我所拥有的:
import unittest
from unittest import mock
class Test(unittest.TestCase):
group_data = []
user_id = 'test_user_id'
def mock_dependencies(self, x):
x.__user_id = mock.PropertyMock(return_value=self.user_id)
x.__get_group_members = mock.MagicMock(return_value=self.group_data)
def first_test(self):
x = A(('name', 'group'))
self.mock_dependencies(x)
x.is_member_of('test_group')
当我调用x.is\u member\u of()
时,模拟没有按预期工作 您可以在Python中访问private属性,因为private和protected受约定保护。-您需要的基本上是使用\u ClassName\u private\u attribute\u name
,因为python执行重命名是为了实现约定
示例(返回MagicMock):
with mock.patch.object(Class, '_ClassName__private_attribute_name', return_value='value') as obj_mock:
pass
with mock.patch.object(Class, '_ClassName__private_attribute_name', new_callable=PropertyMock) as obj_mock:
obj_mock.return_value = 'string value'
from unittest.mock import patch, PropertyMock
from unittest import TestCase, main
class Private:
__attr = 'hello'
class PrivateTest(TestCase):
@patch.object(Private, '_Private__attr', new_callable=PropertyMock)
def test_private_attribute_value_change_decorator_success(self, private_mock):
obj = Private()
private_mock.return_value = 'string'
self.assertEqual('string', obj._Private__attr)
def test_private_attribute_value_change_context_manager_success(self):
with patch.object(Private, '_Private__attr', new_callable=PropertyMock) as o_mock:
obj = Private()
o_mock.return_value = 'mocked value'
self.assertEqual('mocked value', obj._Private__attr)
if __name__ == '__main__':
main()
from unittest import TestCase, mock, main
class A:
__user_id = 3
def __init__(self, user, group):
"""
Your logic is missing - obviously
:param user:
:param group:
"""
def __get_group_members(self):
"""
Your logic is missing - obviously
:return:
"""
return ['user_1', 'user_2']
def is_member_of(self, group_name):
members = self.__get_group_members(group_name)
# will return if the user is a member of the group
return self.__user_id in members
class GroupTest(TestCase):
group_data = [1, 2]
user_id = 'test_user_id'
@mock.patch.object(A, '_A__get_group_members')
@mock.patch.object(A, '_A__user_id', new_callable=mock.PropertyMock)
def test_this_is_my_first_success(self, user_id_mock: mock.PropertyMock, get_group_members_mock: mock.MagicMock):
get_group_members_mock.return_value = self.group_data
user_id_mock.return_value = 3
x = A('user_3', 'this_group')
self.assertEqual(False, x.is_member_of('test_group'))
@mock.patch.object(A, '_A__get_group_members')
@mock.patch.object(A, '_A__user_id', new_callable=mock.PropertyMock)
def test_this_is_my_first_failure(self, user_id_mock: mock.PropertyMock, get_group_members_mock: mock.MagicMock):
get_group_members_mock.return_value = self.group_data
user_id_mock.return_value = 1
x = A('user_1', 'this_group')
self.assertEqual(True, x.is_member_of('test_group'))
if __name__ == '__main__':
main()
示例(返回原始值):
with mock.patch.object(Class, '_ClassName__private_attribute_name', return_value='value') as obj_mock:
pass
with mock.patch.object(Class, '_ClassName__private_attribute_name', new_callable=PropertyMock) as obj_mock:
obj_mock.return_value = 'string value'
from unittest.mock import patch, PropertyMock
from unittest import TestCase, main
class Private:
__attr = 'hello'
class PrivateTest(TestCase):
@patch.object(Private, '_Private__attr', new_callable=PropertyMock)
def test_private_attribute_value_change_decorator_success(self, private_mock):
obj = Private()
private_mock.return_value = 'string'
self.assertEqual('string', obj._Private__attr)
def test_private_attribute_value_change_context_manager_success(self):
with patch.object(Private, '_Private__attr', new_callable=PropertyMock) as o_mock:
obj = Private()
o_mock.return_value = 'mocked value'
self.assertEqual('mocked value', obj._Private__attr)
if __name__ == '__main__':
main()
from unittest import TestCase, mock, main
class A:
__user_id = 3
def __init__(self, user, group):
"""
Your logic is missing - obviously
:param user:
:param group:
"""
def __get_group_members(self):
"""
Your logic is missing - obviously
:return:
"""
return ['user_1', 'user_2']
def is_member_of(self, group_name):
members = self.__get_group_members(group_name)
# will return if the user is a member of the group
return self.__user_id in members
class GroupTest(TestCase):
group_data = [1, 2]
user_id = 'test_user_id'
@mock.patch.object(A, '_A__get_group_members')
@mock.patch.object(A, '_A__user_id', new_callable=mock.PropertyMock)
def test_this_is_my_first_success(self, user_id_mock: mock.PropertyMock, get_group_members_mock: mock.MagicMock):
get_group_members_mock.return_value = self.group_data
user_id_mock.return_value = 3
x = A('user_3', 'this_group')
self.assertEqual(False, x.is_member_of('test_group'))
@mock.patch.object(A, '_A__get_group_members')
@mock.patch.object(A, '_A__user_id', new_callable=mock.PropertyMock)
def test_this_is_my_first_failure(self, user_id_mock: mock.PropertyMock, get_group_members_mock: mock.MagicMock):
get_group_members_mock.return_value = self.group_data
user_id_mock.return_value = 1
x = A('user_1', 'this_group')
self.assertEqual(True, x.is_member_of('test_group'))
if __name__ == '__main__':
main()
Class
是对类本身的引用,而不是对实例的引用
完整示例:
with mock.patch.object(Class, '_ClassName__private_attribute_name', return_value='value') as obj_mock:
pass
with mock.patch.object(Class, '_ClassName__private_attribute_name', new_callable=PropertyMock) as obj_mock:
obj_mock.return_value = 'string value'
from unittest.mock import patch, PropertyMock
from unittest import TestCase, main
class Private:
__attr = 'hello'
class PrivateTest(TestCase):
@patch.object(Private, '_Private__attr', new_callable=PropertyMock)
def test_private_attribute_value_change_decorator_success(self, private_mock):
obj = Private()
private_mock.return_value = 'string'
self.assertEqual('string', obj._Private__attr)
def test_private_attribute_value_change_context_manager_success(self):
with patch.object(Private, '_Private__attr', new_callable=PropertyMock) as o_mock:
obj = Private()
o_mock.return_value = 'mocked value'
self.assertEqual('mocked value', obj._Private__attr)
if __name__ == '__main__':
main()
from unittest import TestCase, mock, main
class A:
__user_id = 3
def __init__(self, user, group):
"""
Your logic is missing - obviously
:param user:
:param group:
"""
def __get_group_members(self):
"""
Your logic is missing - obviously
:return:
"""
return ['user_1', 'user_2']
def is_member_of(self, group_name):
members = self.__get_group_members(group_name)
# will return if the user is a member of the group
return self.__user_id in members
class GroupTest(TestCase):
group_data = [1, 2]
user_id = 'test_user_id'
@mock.patch.object(A, '_A__get_group_members')
@mock.patch.object(A, '_A__user_id', new_callable=mock.PropertyMock)
def test_this_is_my_first_success(self, user_id_mock: mock.PropertyMock, get_group_members_mock: mock.MagicMock):
get_group_members_mock.return_value = self.group_data
user_id_mock.return_value = 3
x = A('user_3', 'this_group')
self.assertEqual(False, x.is_member_of('test_group'))
@mock.patch.object(A, '_A__get_group_members')
@mock.patch.object(A, '_A__user_id', new_callable=mock.PropertyMock)
def test_this_is_my_first_failure(self, user_id_mock: mock.PropertyMock, get_group_members_mock: mock.MagicMock):
get_group_members_mock.return_value = self.group_data
user_id_mock.return_value = 1
x = A('user_1', 'this_group')
self.assertEqual(True, x.is_member_of('test_group'))
if __name__ == '__main__':
main()
对示例的修改:
with mock.patch.object(Class, '_ClassName__private_attribute_name', return_value='value') as obj_mock:
pass
with mock.patch.object(Class, '_ClassName__private_attribute_name', new_callable=PropertyMock) as obj_mock:
obj_mock.return_value = 'string value'
from unittest.mock import patch, PropertyMock
from unittest import TestCase, main
class Private:
__attr = 'hello'
class PrivateTest(TestCase):
@patch.object(Private, '_Private__attr', new_callable=PropertyMock)
def test_private_attribute_value_change_decorator_success(self, private_mock):
obj = Private()
private_mock.return_value = 'string'
self.assertEqual('string', obj._Private__attr)
def test_private_attribute_value_change_context_manager_success(self):
with patch.object(Private, '_Private__attr', new_callable=PropertyMock) as o_mock:
obj = Private()
o_mock.return_value = 'mocked value'
self.assertEqual('mocked value', obj._Private__attr)
if __name__ == '__main__':
main()
from unittest import TestCase, mock, main
class A:
__user_id = 3
def __init__(self, user, group):
"""
Your logic is missing - obviously
:param user:
:param group:
"""
def __get_group_members(self):
"""
Your logic is missing - obviously
:return:
"""
return ['user_1', 'user_2']
def is_member_of(self, group_name):
members = self.__get_group_members(group_name)
# will return if the user is a member of the group
return self.__user_id in members
class GroupTest(TestCase):
group_data = [1, 2]
user_id = 'test_user_id'
@mock.patch.object(A, '_A__get_group_members')
@mock.patch.object(A, '_A__user_id', new_callable=mock.PropertyMock)
def test_this_is_my_first_success(self, user_id_mock: mock.PropertyMock, get_group_members_mock: mock.MagicMock):
get_group_members_mock.return_value = self.group_data
user_id_mock.return_value = 3
x = A('user_3', 'this_group')
self.assertEqual(False, x.is_member_of('test_group'))
@mock.patch.object(A, '_A__get_group_members')
@mock.patch.object(A, '_A__user_id', new_callable=mock.PropertyMock)
def test_this_is_my_first_failure(self, user_id_mock: mock.PropertyMock, get_group_members_mock: mock.MagicMock):
get_group_members_mock.return_value = self.group_data
user_id_mock.return_value = 1
x = A('user_1', 'this_group')
self.assertEqual(True, x.is_member_of('test_group'))
if __name__ == '__main__':
main()
如果您知道您将在所有测试用例中模拟这两个属性,那么您可以在类级别添加decorator,并期望像wise这样的参数
在通过\uuuu init\uuuu
或任何其他方法设置属性的情况下,您只需如下所示对其进行更改
from unittest import TestCase, mock, main
class A:
def __init__(self, user, group):
"""
Your logic is missing - obviously
:param user:
:param group:
"""
def __get_group_members(self):
"""
Your logic is missing - obviously
:return:
"""
return ['user_1', 'user_2']
def is_member_of(self, group_name):
members = self.__get_group_members(group_name)
# will return if the user is a member of the group
return self.__user_id in members
class GroupTest(TestCase):
group_data = [1, 2]
user_id = 'test_user_id'
@mock.patch.object(A, '_A__get_group_members')
def test_this_is_my_first_success(self, get_group_members_mock: mock.MagicMock):
x = A('user_3', 'this_group')
x._A__user_id = 5
get_group_members_mock.return_value = self.group_data
self.assertEqual(False, x.is_member_of('test_group'))
@mock.patch.object(A, '_A__get_group_members')
def test_this_is_my_first_failure(self, get_group_members_mock: mock.MagicMock):
get_group_members_mock.return_value = self.group_data
x = A('user_1', 'this_group')
x._A__user_id = 1
self.assertEqual(True, x.is_member_of('test_group'))
if __name__ == '__main__':
main()
当尝试访问成员时,“obj.\u private\u attribute\u name”会给出
,但由于某些原因,它不是指定为返回值(“值”)的值。如何修复此问题?您正在尝试使用PropertyMock
-更新的答案。这次得到了`。在返回值赋值后立即打印“obj_mock.\uu private_attribute_name”。让我为您检查一下。谢谢您的帮助