У меня есть приспособление, которое создает 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'
.
Интересно, возможно ли это to 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