PyQt5+pytest测试中无法通过代码点击对话框按钮关闭弹窗问题
PyQt5对话框测试问题分析与解决方案
问题原因拆解
1. 测试挂起无法完成
点击主按钮后,launchDialog中调用的self.dialog.exec()是模态对话框的阻塞式调用,会启动独立事件循环并卡住当前线程。测试函数中qtbot.mouseClick(app.button)后的代码(包括等待和对话框按钮点击)完全没有执行机会,直到对话框手动关闭才会继续。另外,测试函数手动创建QtBot(app)是错误操作,应使用fixture注入的qtbot实例。
2. 测试时仅显示对话框、看不到原窗口
测试fixture中创建的Foo实例未调用show()方法,主窗口不会渲染;但对话框是模态窗口,会强制抢占前台显示,因此只看到对话框。
修改后的测试代码
方案1:适配模态对话框的阻塞特性
import pytest from pytestqt.qtbot import QtBot from PyQt5 import QtCore from foo import Foo @pytest.fixture def app(qtbot): foo = Foo() foo.show() # 显示主窗口,解决原窗口不可见问题 qtbot.addWidget(foo) return foo def test_button(app, qtbot): def click_dialog_button(): # 定时器触发对话框按钮点击,绕过exec()的线程阻塞 qtbot.mouseClick(app.dialog.button, QtCore.Qt.LeftButton) # 提前设置定时器,确保对话框显示后自动触发点击 QtCore.QTimer.singleShot(100, click_dialog_button) # 点击主按钮,触发模态对话框弹出(此时线程会被exec()阻塞) qtbot.mouseClick(app.button, QtCore.Qt.LeftButton) # 等待对话框关闭,确保测试流程完成 qtbot.waitUntil(lambda: not app.dialog.isVisible(), timeout=5000)
方案2:调整对话框为非模态(仅测试场景)
如果允许修改原代码的弹窗逻辑,可将exec()改为show(),避免线程阻塞:
# 修改foo.py中的launchDialog方法 def launchDialog(self): self.dialog = FooDialog(parent=self) self.dialog.show() # 替换exec()为show(),非模态弹窗
对应测试代码简化为:
def test_button(app, qtbot): qtbot.mouseClick(app.button, QtCore.Qt.LeftButton) # 等待对话框可见后直接点击 qtbot.waitUntil(lambda: app.dialog.isVisible(), timeout=5000) qtbot.mouseClick(app.dialog.button, QtCore.Qt.LeftButton)
内容的提问来源于stack exchange,提问作者user1102665
相关产品推荐
相关产品推荐

