模拟整个 python class
Mock entire python class
我想在 python 中做一个简单的测试,但我无法弄清楚如何完成模拟过程。
这是 class 和 def 代码:
class FileRemoveOp(...)
@apply_defaults
def __init__(
self,
source_conn_keys,
source_conn_id='conn_default',
*args, **kwargs):
super(v4FileRemoveOperator, self).__init__(*args, **kwargs)
self.source_conn_keys = source_conn_keys
self.source_conn_id = source_conn_id
def execute (self, context)
source_conn = Connection(conn_id)
try:
for source_conn_key in self.source_keys:
if not source_conn.check_for_key(source_conn_key):
logging.info("The source key does not exist")
source_conn.remove_file(source_conn_key,'')
finally:
logging.info("Remove operation successful.")
这是我对执行函数的测试:
@mock.patch('main.Connection')
def test_remove_execute(self,MockConn):
mock_coon = MockConn.return_value
mock_coon.value = #I'm not sure what to put here#
remove_operator = FileRemoveOp(...)
remove_operator.execute(self)
由于 execute 方法尝试建立连接,我需要模拟它,我不想建立真正的连接,只是 return 一些模拟.我该怎么做?我习惯于在 Java 中进行测试,但我从未在 python 中进行过测试。
首先,了解您始终需要在 unittest.mock
文档中所述使用您尝试模拟的东西的地方进行模拟是非常重要的。
The basic principle is that you patch where an object is looked up,
which is not necessarily the same place as where it is defined.
接下来您需要做的是 return 一个 MagicMock
实例作为修补对象的 return_value
。因此,为了总结这一点,您需要使用以下序列。
- 补丁对象
- 准备
MagicMock
以供使用
- return 我们刚刚创建的
MagicMock
return_value
这里是一个项目的简单示例。
connection.py(Class我们想Mock)
class Connection(object):
def execute(self):
return "Connection to server made"
file.py(使用Class的地方)
from project.connection import Connection
class FileRemoveOp(object):
def __init__(self, foo):
self.foo = foo
def execute(self):
conn = Connection()
result = conn.execute()
return result
tests/test_file.py
import unittest
from unittest.mock import patch, MagicMock
from project.file import FileRemoveOp
class TestFileRemoveOp(unittest.TestCase):
def setUp(self):
self.fileremoveop = FileRemoveOp('foobar')
@patch('project.file.Connection')
def test_execute(self, connection_mock):
# Create a new MagickMock instance which will be the
# `return_value` of our patched object
connection_instance = MagicMock()
connection_instance.execute.return_value = "testing"
# Return the above created `connection_instance`
connection_mock.return_value = connection_instance
result = self.fileremoveop.execute()
expected = "testing"
self.assertEqual(result, expected)
def test_not_mocked(self):
# No mocking involved will execute the `Connection.execute` method
result = self.fileremoveop.execute()
expected = "Connection to server made"
self.assertEqual(result, expected)
我发现这个简单的解决方案在 python3 中有效:您可以在第一次导入之前替换整个 class。假设我必须从 real.manager
中模拟 class 'Manager'
class MockManager:
...
import real.manager
real.manager.Manager = MockManager
如果没有更好的地方,可以在init.py 中进行替换。
它也可能在 python2 中工作,但我没有检查。
我想在 python 中做一个简单的测试,但我无法弄清楚如何完成模拟过程。
这是 class 和 def 代码:
class FileRemoveOp(...)
@apply_defaults
def __init__(
self,
source_conn_keys,
source_conn_id='conn_default',
*args, **kwargs):
super(v4FileRemoveOperator, self).__init__(*args, **kwargs)
self.source_conn_keys = source_conn_keys
self.source_conn_id = source_conn_id
def execute (self, context)
source_conn = Connection(conn_id)
try:
for source_conn_key in self.source_keys:
if not source_conn.check_for_key(source_conn_key):
logging.info("The source key does not exist")
source_conn.remove_file(source_conn_key,'')
finally:
logging.info("Remove operation successful.")
这是我对执行函数的测试:
@mock.patch('main.Connection')
def test_remove_execute(self,MockConn):
mock_coon = MockConn.return_value
mock_coon.value = #I'm not sure what to put here#
remove_operator = FileRemoveOp(...)
remove_operator.execute(self)
由于 execute 方法尝试建立连接,我需要模拟它,我不想建立真正的连接,只是 return 一些模拟.我该怎么做?我习惯于在 Java 中进行测试,但我从未在 python 中进行过测试。
首先,了解您始终需要在 unittest.mock
文档中所述使用您尝试模拟的东西的地方进行模拟是非常重要的。
The basic principle is that you patch where an object is looked up, which is not necessarily the same place as where it is defined.
接下来您需要做的是 return 一个 MagicMock
实例作为修补对象的 return_value
。因此,为了总结这一点,您需要使用以下序列。
- 补丁对象
- 准备
MagicMock
以供使用 - return 我们刚刚创建的
MagicMock
return_value
这里是一个项目的简单示例。
connection.py(Class我们想Mock)
class Connection(object):
def execute(self):
return "Connection to server made"
file.py(使用Class的地方)
from project.connection import Connection
class FileRemoveOp(object):
def __init__(self, foo):
self.foo = foo
def execute(self):
conn = Connection()
result = conn.execute()
return result
tests/test_file.py
import unittest
from unittest.mock import patch, MagicMock
from project.file import FileRemoveOp
class TestFileRemoveOp(unittest.TestCase):
def setUp(self):
self.fileremoveop = FileRemoveOp('foobar')
@patch('project.file.Connection')
def test_execute(self, connection_mock):
# Create a new MagickMock instance which will be the
# `return_value` of our patched object
connection_instance = MagicMock()
connection_instance.execute.return_value = "testing"
# Return the above created `connection_instance`
connection_mock.return_value = connection_instance
result = self.fileremoveop.execute()
expected = "testing"
self.assertEqual(result, expected)
def test_not_mocked(self):
# No mocking involved will execute the `Connection.execute` method
result = self.fileremoveop.execute()
expected = "Connection to server made"
self.assertEqual(result, expected)
我发现这个简单的解决方案在 python3 中有效:您可以在第一次导入之前替换整个 class。假设我必须从 real.manager
中模拟 class 'Manager'class MockManager:
...
import real.manager
real.manager.Manager = MockManager
如果没有更好的地方,可以在init.py 中进行替换。 它也可能在 python2 中工作,但我没有检查。