pytest-dev / pytest-qt

pytest plugin for Qt (PyQt5/PyQt6 and PySide2/PySide6) application testing
https://pytest-qt.readthedocs.io
MIT License
409 stars 70 forks source link

How to automatically select documents from QFileDialog? #475

Closed ningwana closed 1 year ago

ningwana commented 1 year ago

I want to test my Graphical User Interface with the qtbot from pytest-qt.

I am new to testing in general and i could need some guidance on how to start writing these tests.

I want the bot to click on the file icon, then a QFileDialog opens, as in the picture below and the bot needs to select a pdf.

I already looked for documentation and what i found was not really helpful, i didn't understand how to set the qtbot up.

image

from PySide2.QtWidgets import QMainWindow, QPushButton, QApplication, QFileDialog

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.button = ''
        btn = QPushButton('Open File', self)
        btn.move(10, 10)
        btn.clicked.connect(self.open_file)
        self.resize(420, 450)

    def open_file(self):
        pdf_dialog_obj = QFileDialog.getOpenFileNames(self, "Open Pdf", "/Downloads", "Pdf Files (*.pdf)",)
        pdf_path = pdf_dialog_obj[0]
        print(pdf_path)

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    MW = MainWindow()
    MW.show()
    sys.exit(app.exec_())

Like: https://stackoverflow.com/questions/58731798/gui-testing-in-pyside2-with-qtbot

nicoddemus commented 1 year ago

You need to write a test file and use qtbot to create and interact with your MainWindow, see the tutorial.

ningwana commented 1 year ago

Thank you very much for your answer. @nicoddemus

Sorry my description may not be clear.

It means how to let qtbot automatically select files from the QFileDialog pop-up window.

Here's an example I added:

=======================================================

main_window.py

from PySide2.QtWidgets import QMainWindow, QPushButton, QApplication, QFileDialog

class MainWindow(QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()
        self.button = QPushButton('Open File', self)
        self.button.move(10, 10)
        self.button.clicked.connect(self.open_file)
        self.resize(420, 450)

    def open_file(self):
        filename, _ = QFileDialog.getOpenFileName(self, "Open Pdf", "", "Pdf Files (*.pdf)",)
        print(filename)

if __name__ == '__main__':
    import sys

    app = QApplication(sys.argv)
    MW = MainWindow()
    MW.show()
    sys.exit(app.exec_())

================

test_button.py

import pytest
from PySide2 import QtCore

from src import main_window

@pytest.fixture(scope='function')
def creat_window(qtbot):
    main = main_window.MainWindow()
    qtbot.addWidget(main)
    main.show()
    qtbot.wait_for_window_shown(main)
    return main

def test_open_file(qtbot, creat_window):
    main = creat_window
    qtbot.mouseClick(main.button, QtCore.Qt.LeftButton)
    #How do I get qtbot to automatically select a file and have the same value as I expect?
nicoddemus commented 1 year ago

See https://pytest-qt.readthedocs.io/en/latest/note_dialogs.html

The principle is the same, but you would mock QFileDialog.getOpenFileName instead.

ningwana commented 1 year ago

@nicoddemus

i got it and I know how to write it. thanks again.

(Because I didn't know monkeypatch before...)

def test_open_file(qtbot, creat_window):
    main = creat_window
    qtbot.mouseClick(main.button, QtCore.Qt.LeftButton)
    file_path = r"/Downloads/test.pdf"
    file_type = 'Pdf Files (*.pdf)'
    # The code under replaces the :func:`QFileDialog.getOpenFileName` function by a ``lambda`` which always returns "file_path, file_type".
    monkeypatch.setattr(QFileDialog, "getOpenFileName", lambda *args: (file_path, file_type))
    ......