GUIアプリケーションのメニューから、正しいメソッドが呼び出されていることを確認するテストです。pytest-qtのissueに書かれていますが、実際にメニューを選択することは難しいとのことで、メニュー項目に割り当てられているQActionオブジェクトにtriggerイベントを発生させること代用することを勧められています。
前提条件
開発環境
対象とするGUIアプリケーションはPython+Qtで開発されているとします。Qtのライブラリは以下のいずれにも対応するとのことですが、PySide2環境で検証しました。
- PySide2
- PySide
- PyQt5
- PyQt4
インストールするパッケージ
以下のパッケージが必要です。
pip install pytest pytest-qt pytest-mock
作業手順
サンプルのプログラム
メニューが「メニュー」一つ、それにメニュー項目が「アクション」の一つのみのシンプルなプログラムです。
qiita.py
from PySide2.QtWidgets import QApplication
from PySide2.QtWidgets import QMainWindow
from PySide2.QtWidgets import QAction
from PySide2.QtWidgets import QMenu
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
menu = QMenu('メニュー', self)
action = QAction('アクション', menu)
action.setObjectName('action')
action.triggered.connect(self.action_function)
menu.addAction(action)
self.menuBar().addMenu(menu)
def action_function(self):
print('アクション')
return
def main() -> None:
app = QApplication()
window = MainWindow()
window.show()
app.exec_()
if __name__ == '__main__':
main()
注意点としては、テストスクリプトからメニュー項目のQActionオブジェクトを検索するために、以下を設定しています。
- メニュー項目のQActionオブジェクトにオブジェクト名を設定
- MainWindow(QWindowのサブクラス), QMenu, QActionが親子関係
テストスクリプト
「アクション」項目に正しいメソッド(ここではaction_function)が設定されているかを確認するテストスクリプトです。
test_qiita.py
from PySide2.QtWidgets import QAction
from qiita import MainWindow
def test_qiita(qtbot, mocker):
window = MainWindow()
mocker.patch.object(MainWindow, 'action_function')
window.findChild(QAction, 'action').trigger()
MainWindow.action_function.assert_called_once_with()
テストスクリプトは以下の動作をします。
- 呼び出されるべきaction_functionをモックに置き換えます。
- テスト対象のメニュー項目に該当するQActionオブジェクトをfindChildメソッドで検索して、trigger()イベントを発生します。
- 置き換えたモックが呼び出された回数を確認します。
テストの実行
以下のコマンドを実行します。
$ pytest test_qiita.py
以下のように出力されます。
============================= test session starts ==============================
platform linux -- Python 3.6.7, pytest-4.1.1, py-1.7.0, pluggy-0.8.1
cachedir: .pytest_cache
PySide2 5.12.0 -- Qt runtime 5.12.0 -- Qt compiled 5.12.0
rootdir: /home/user1/projects, inifile:
plugins: qt-3.2.2, mock-1.10.0
collected 1 item
test_qiita.py::test_qiita PASSED [100%]
=========================== 1 passed in 0.19 seconds ===========================