模拟方法调用 Python
Mocking Method Calls In Python
我一直在搜索堆栈交换和网络以了解如何执行此操作,但我不明白如何模拟方法的行为。我正在尝试为我的自定义 class 模拟 openpyxl 行为和行为。这是我的尝试:
import unittest
from unittest.mock import MagicMock
import openpyxl
from MyPythonFile import MyClass
class TestMyClass(unittest.TestCase):
def test_myclass(self):
myclass = MyClass()
wb = openpyxl.workbook()
ws = openpyxl.worksheet()
wbPath = 'wbPath'
openpyxl.load_workbook(wbPath, data_only = True) = MagicMock(return_value=wb)
当我尝试最后一行时,出现错误 "can't assign to function call"。我需要使用 patch.object('openpyxl','load_workbook')
吗?我习惯于在 Java 中使用 Groovy 进行模拟,这非常简单。
*编辑:想根据@alxwrd
的回复添加测试的最终版本
import unittest
from unittest.mock import MagicMock
import openpyxl
import configparser
from MyPythonFile import MyClass
class TestMyClass(unittest.TestCase):
def test_myclass(self):
myclass = MyClass()
wb = openpyxl.workbook()
ws = openpyxl.worksheet()
config = configparser.ConfigParser()
openpyxl.load_workbook = MagicMock(return_value=wb)
wb.get_sheet_by_name = MagicMock(return_value=ws)
config.sections() = MagicMock(return_value=['Section1'])
config.get = MagicMock(side_effect=['Value1','Value2'])
注意 config.get 给出多个 returns 与 side_effect 参数,所以如果 config.get()
在代码中调用一次它 returns 'Value1'
并且当 config.get()
被第二次调用时 returns 'Value2'
.
您无法覆盖函数 调用,但您可以覆盖函数本身。
来自docs:
>>> from unittest.mock import MagicMock
>>> thing = ProductionClass()
>>> thing.method = MagicMock(return_value=3)
>>> thing.method(3, 4, 5, key='value')
3
>>> thing.method.assert_called_with(3, 4, 5, key='value')
所以在你的情况下:
openpyxl.load_workbook = MagicMock(return_value=wb)
您不必在单元测试中导入要模拟的目标。使用 patch to mock the target. Let's assume your code has this import statement: import openpyxl
. Patch then can be used in your test as a decorator:
import unittest
from unittest import mock
from MyPythonFile import MyClass
class TestMyClass(unittest.TestCase):
@mock.patch('MyPythonFile.openpyxl')
def test_myclass(self, openpyxl_mock):
wb_dummy = 'foo'
openpyxl_mock.load_workbook.return_value = wb_dummy
myclass = MyClass()
myclass.load_workbook() # assuming this calls openpyxl.load_workbook()
请注意,您必须向将获取模拟对象的测试方法添加一个参数。
或作为 context manager:
import unittest
from unittest import mock
from MyPythonFile import MyClass
class TestMyClass(unittest.TestCase):
def test_myclass(self):
with mock.patch('MyPythonFile.openpyxl') as openpyxl_mock:
wb_dummy = 'foo'
openpyxl_mock.load_workbook.return_value = wb_dummy
myclass = MyClass()
myclass.load_workbook() # assuming this calls openpyxl.load_workbook()
我一直在搜索堆栈交换和网络以了解如何执行此操作,但我不明白如何模拟方法的行为。我正在尝试为我的自定义 class 模拟 openpyxl 行为和行为。这是我的尝试:
import unittest
from unittest.mock import MagicMock
import openpyxl
from MyPythonFile import MyClass
class TestMyClass(unittest.TestCase):
def test_myclass(self):
myclass = MyClass()
wb = openpyxl.workbook()
ws = openpyxl.worksheet()
wbPath = 'wbPath'
openpyxl.load_workbook(wbPath, data_only = True) = MagicMock(return_value=wb)
当我尝试最后一行时,出现错误 "can't assign to function call"。我需要使用 patch.object('openpyxl','load_workbook')
吗?我习惯于在 Java 中使用 Groovy 进行模拟,这非常简单。
*编辑:想根据@alxwrd
的回复添加测试的最终版本import unittest
from unittest.mock import MagicMock
import openpyxl
import configparser
from MyPythonFile import MyClass
class TestMyClass(unittest.TestCase):
def test_myclass(self):
myclass = MyClass()
wb = openpyxl.workbook()
ws = openpyxl.worksheet()
config = configparser.ConfigParser()
openpyxl.load_workbook = MagicMock(return_value=wb)
wb.get_sheet_by_name = MagicMock(return_value=ws)
config.sections() = MagicMock(return_value=['Section1'])
config.get = MagicMock(side_effect=['Value1','Value2'])
注意 config.get 给出多个 returns 与 side_effect 参数,所以如果 config.get()
在代码中调用一次它 returns 'Value1'
并且当 config.get()
被第二次调用时 returns 'Value2'
.
您无法覆盖函数 调用,但您可以覆盖函数本身。
来自docs:
>>> from unittest.mock import MagicMock >>> thing = ProductionClass() >>> thing.method = MagicMock(return_value=3) >>> thing.method(3, 4, 5, key='value') 3 >>> thing.method.assert_called_with(3, 4, 5, key='value')
所以在你的情况下:
openpyxl.load_workbook = MagicMock(return_value=wb)
您不必在单元测试中导入要模拟的目标。使用 patch to mock the target. Let's assume your code has this import statement: import openpyxl
. Patch then can be used in your test as a decorator:
import unittest
from unittest import mock
from MyPythonFile import MyClass
class TestMyClass(unittest.TestCase):
@mock.patch('MyPythonFile.openpyxl')
def test_myclass(self, openpyxl_mock):
wb_dummy = 'foo'
openpyxl_mock.load_workbook.return_value = wb_dummy
myclass = MyClass()
myclass.load_workbook() # assuming this calls openpyxl.load_workbook()
请注意,您必须向将获取模拟对象的测试方法添加一个参数。
或作为 context manager:
import unittest
from unittest import mock
from MyPythonFile import MyClass
class TestMyClass(unittest.TestCase):
def test_myclass(self):
with mock.patch('MyPythonFile.openpyxl') as openpyxl_mock:
wb_dummy = 'foo'
openpyxl_mock.load_workbook.return_value = wb_dummy
myclass = MyClass()
myclass.load_workbook() # assuming this calls openpyxl.load_workbook()