python - 是否可以修补以前创建的模拟调用的方法?
问题描述
我有在初始化期间创建mocker.Mock
而不是对象的夹具。引用存储在属性中。在我的测试中,我检查是否调用了正确的函数。参数化测试运行良好,直到我遇到应该调用方法的条件。现在有一个模拟。gui.Menu
gui.Buttons
Buttons.menu
gui.Buttons.add
gui.Menu
import pytest
from project import gui
@pytest.fixture
def buttons(mocker):
mocker.patch('project.gui.tk.Frame.__init__', return_value=None)
mocker.patch('project.gui.tk.Button')
return gui.Buttons(mocker.Mock())
@pytest.mark.parametrize('value,patched',(
(None, 'project.gui.show_no_connection'),
(False, 'project.gui.Buttons.process_data'),
(True, 'pytest.Mock.show_error'),
))
def test_add_calls_function(buttons, value, patched, mocker):
mocker.patch('project.gui.Buttons.exist_check', return_value=value)
mocked = mocker.patch(patched)
buttons.add()
mocked.assert_called_once()
使用真实对象,我可以(True, 'project.gui.Menu.show_error')
在里面写@pytest.mark.parametrize
而(True, 'pytest.Mock.show_error')
不是不起作用并产生ModuleNotFoundError: No module named 'pytest.Mock'
.
我想知道是否可以patch
在我的夹具中创建模拟对象以使其像其他参数化示例一样工作。甚至可能吗?如果我的理解是错误的,请纠正我。
测试代码如下:
import tkinter as tk
import tkinter.messagebox as msg
from project.connection import Database
def show_no_connection():
msg.showerror('Error', 'Could not perform operation. Try again later.')
class Menu(tk.Tk):
def __init__(self):
super().__init__()
self.form = Form()
def show_error(self, message):
self.form.clear()
msg.showerror('Error', message)
class Form(tk.Frame):
def clear(self):
print('Clearing...')
def get(self):
return {'Title': 'Test', 'ISBN': 87327837823}
class Buttons(tk.Frame):
def __init__(self, menu):
super().__init__(menu)
self.menu = menu
def process_data(self, data, operation):
operation(data)
def add(self):
data = self.menu.form.get()
exists = self.exist_check(data.get('ISBN', None))
if exists is None:
show_no_connection()
else:
if exists:
self.menu.show_error(
'Record with set ISBN already exists in database.')
else:
self.process_data(data, Database().add)
@staticmethod
def exist_check(number):
if number:
return Database().search({'ISBN': number})
return False
显示错误:
=================================== FAILURES ===================================
_________ test_add_calls_function[True-project.gui.Gui.show_error] _________
buttons = <[AttributeError("'Buttons' object has no attribute '_w'") raised in repr()] Buttons object at 0x7f840114aa10>
value = True, patched = 'project.gui.Gui.show_error'
mocker = <pytest_mock.plugin.MockFixture object at 0x7f840114ab90>
@pytest.mark.parametrize('value,patched',(
(None, 'project.gui.show_no_connection'),
(False, 'project.gui.Buttons.process_data'),
(True, 'project.gui.Gui.show_error'),
))
def test_add_calls_function(buttons, value, patched, mocker):
mocker.patch('project.gui.Buttons.exist_check', return_value=value)
mocked = mocker.patch(patched)
buttons.add()
> mocked.assert_called_once()
E AssertionError: Expected 'show_error' to have been called once. Called 0 times.
tests/test_gui_buttons.py:88: AssertionError
解决方案
我看不出有可能在同一个测试中处理这个问题——你可能需要对最后一次通话进行单独的测试。问题是菜单已经被模拟了,你需要那个特定的菜单模拟来测试函数调用(函数将从那个模拟实例中调用)。
这是一个可能的工作实现:
import pytest
# don't use "from project import gui" here to not make a copy in the test module
# that would be used instead of the mocked one
import project.gui
@pytest.fixture
def menu_mock(mocker):
# gives the possibility to access the menu mock
# we need the return_value to get the instance instead of the class
return mocker.patch('project.gui.Menu').return_value
@pytest.fixture
def buttons(mocker, menu_mock):
mocker.patch('project.gui.tk.Frame.__init__', return_value=None)
mocker.patch('project.gui.tk.Button')
return project.gui.Buttons(menu_mock)
@pytest.mark.parametrize('value, patched',(
(None, 'project.gui.show_no_connection'),
(False, 'project.gui.Buttons.process_data')
))
def test_add_calls_function(buttons, value, patched, mocker):
# unchanged except for the missing parametrize case
mocker.patch('project.gui.Buttons.exist_check', return_value=value)
mocked = mocker.patch(patched)
buttons.add()
mocked.assert_called_once()
def test_add_calls_show_error(buttons, menu_mock, mocker):
mocker.patch('project.gui.Buttons.exist_check', return_value=True)
buttons.add()
# you now have access to the mocked menu instance
menu_mock.show_error.assert_called_once()
推荐阅读
- javascript - 根据MongoDB中引用文档的属性获取所有文档
- android - how to setup exoplayer to play both mp4 and m3u8 depends on url ending
- python - How to stop pandas from appending to existing dataframe on a loop?
- amazon-web-services - How to attach and mount an EBS volume (NVM) in Ec2
- java - Java: Generating Code from WSDL with "ANT" and "AXIS2 1.8.0"
- html - 如何在我的 fontawesome 图标和
元素?
- c# - 可选外键的错误 EFCore 实体配置
- python-3.x - 有没有办法在 Jenkinsfile/Makefile 中指定使用哪个 python 版本?
- mysql - 我已经上传了 MYSQL 数据库中包含 23k 行的 excel,它向我显示错误“读取 ECONNRESET”
- c# - 将材料添加到列表