pythonpython-3.xpyqtpyqt5pytest-qt

How to check correct opening the window after the click by button in pytest-qt


I want to test a module in my project, but I have a some problem with it. I don't know how I can check the correct opening of the window after the button click.

I have the windows SelectAddingBookTypeWindow and AddSchoolBookWindow. I want to check that AddSchoolBookWindow will open after I have clicked on the button called selectBtn.

My current test (I have a problem with the last string because I don't know which method I must use):

@pytest.fixture
def open_window(qtbot):
    def _press_button(window):
        widget = window()
        qtbot.addWidget(widget)
        widget.show()
        qtbot.wait_for_window_shown(widget)
        sleep(3)
        return widget
    return _press_button


class TestSelectAddingBookTypeWindow:
    def test_select_schoolbook(self, open_window, qtbot):
        widget = open_window(SelectAddingBookTypeWindow)
        qtbot.mouseClick(widget.schoolbookSelector, QtCore.Qt.LeftButton)
        qtbot.mouseClick(widget.selectBtn, QtCore.Qt.LeftButton)
        assert widget.close()
        assert AddSchoolBookWindow.isActiveWindow()

My classes: A. SelectAddingBookTypeWindow

class SelectBookTypeWindow(QDialog, Ui_selectBookTypeWindow):
    @logger.catch
    def __init__(self, widget1, widget2):
        super().__init__()
        self.setupUi(self)
        self.selectBtn.clicked.connect(lambda x: self.open_new_window(widget1, widget2))

    @logger.catch
    def open_new_window(self, schoolbook_widget, fictionbook_widget):
        if self.schoolbookSelector.isChecked():
            widget = schoolbook_widget()
        elif self.fictionbookSelector.isChecked():
            widget = fictionbook_widget()
        widget.show()
        self.close()


class SelectAddingBookTypeWindow(SelectBookTypeWindow):
    @logger.catch
    def __init__(self):
        super().__init__(AddSchoolBookWindow, AddFictionBookWindow)

B. AddSchoolBookWindow

class AddSchoolBookWindow(QDialog, Ui_AddSchoolbookWindow):
    @logger.catch
    def __init__(self):
        super().__init__()
        self.setupUi(self)
        self.widgets = [
            self.schoolbookAuthor, self.schoolbookTitle, self.schoolbookPublishHouse,
            self.schoolbookPublishYear, self.schoolbookInvoiceNum, self.schoolbookInvoiceDate, self.schoolbookClass,
            self.schoolbookCount, self.schoolbookPrice
        ]
        self.schoolbookSaveBtn.clicked.connect(lambda _: self.save_book())
        self.schoolbookClearBtn.clicked.connect(lambda _: Utils.clear_fields(self.widgets, self.schoolbookInvoiceDate))
        self.schoolbookCancelBtn.clicked.connect(lambda _: self.close())

    @logger.catch
    def save_book(self):
        field_names = Config.COLUMNS['SchoolBook']
        user_data = list(map(lambda x: x.text(), self.widgets))
        book_sum = Utils.calculate_book_sum(user_data)
        user_data.append(str(book_sum))
        book = dict(zip(field_names[1:], user_data))
        db = DatabaseManager(Config.PATHES['TO_DATABASE']['PROD'])
        model = Schoolbook('SchoolBook', db.connection)
        model.insert_book(book)
        logger.success(f'The {book} success add in the database')
        model.model.select()

This is a little part of full code but full code doesn't solve with this problem.


Solution

  • The problem in your case is that the widget is not accessible since it is a local variable, I also doubt that the window will be shown as it should be removed a moment later, so to access it I will create a property:

    class SelectBookTypeWindow(QtWidgets.QDialog, Ui_selectBookTypeWindow):
        def __init__(self, widget1, widget2):
            super().__init__()
            self.setupUi(self)
            self.selectBtn.clicked.connect(lambda x: self.open_new_window(widget1, widget2))
    
            self._selected_window = None
    
        @property
        def selected_window(self):
            return self._selected_window
    
        def open_new_window(self, schoolbook_widget, fictionbook_widget):
            if self.schoolbookSelector.isChecked():
                self._selected_window = schoolbook_widget()
            elif self.fictionbookSelector.isChecked():
                self._selected_window = fictionbook_widget()
            if self.selected_window is not None:
                self.selected_window.show()
                self.close()
    

    And then in the test you should verify that selected_window is not None and its base class is AddSchoolBookWindow, also avoid using time.sleep(), in the case of the tests use QTest.qWait()

    import pytest
    from PyQt5 import QtCore, QtTest
    
    from your_package import AddSchoolBookWindow, SelectAddingBookTypeWindow
    
    
    @pytest.fixture
    def open_window(qtbot):
        def callback(window):
            widget = window()
            qtbot.addWidget(widget)
            widget.show()
            qtbot.wait_for_window_shown(widget)
            QtTest.QTest.qWait(3 * 1000)
            return widget
    
        return callback
    
    
    class TestSelectAddingBookTypeWindow:
        def test_select_schoolbook(self, open_window, qtbot):
            widget = open_window(SelectAddingBookTypeWindow)
            assert widget.isVisible()
            qtbot.mouseClick(widget.schoolbookSelector, QtCore.Qt.LeftButton)
            qtbot.mouseClick(widget.selectBtn, QtCore.Qt.LeftButton)
            assert widget.isHidden()
            assert widget.selected_window is not None
            assert isinstance(widget.selected_window, AddSchoolBookWindow)
            assert widget.selected_window.isVisible()