Pytest仅收集测试用例未展示测试结果问题求助
问题:Pytest收集到测试用例但不展示执行结果
刚装完Pytest,运行针对Python Qt代码的单元测试时,Pytest只提示已收集测试用例,但完全不输出测试通过或失败的结果。相关代码如下:
sos_game.py
from PyQt5.QtWidgets import QWidget, QMainWindow, QApplication, QGridLayout, QPushButton, QLabel, QSpinBox, QVBoxLayout from PyQt5 import uic from board import Ui_MainWindow import sys class SOSGame(QMainWindow): def __init__(self, parent=None): super().__init__(parent) # Set up the user interface from Designer. self.ui = Ui_MainWindow() self.ui.setupUi(self) # Connect the valueChanged signal of the spin box to the setSize method. self.ui.spinBox.setValue(3) self.ui.spinBox.valueChanged.connect(self.setSize) # default game mode self.ui.radioButton.setChecked(True) # Blue Player default settings self.ui.radioButton_7.setChecked(True) self.ui.radioButton_8.setChecked(True) # Red Player default settings self.ui.radioButton_3.setChecked(True) self.ui.radioButton_5.setChecked(True) # setting the buttons to the type of game mode self.ui.radioButton.toggled.connect(lambda: self.setGameMode("Simple")) self.ui.radioButton_2.toggled.connect(lambda: self.setGameMode("General")) # Create the initial game board. self.boardSize = self.ui.spinBox.value() self.createBoard() def createBoard(self): # Clear the existing game board. if hasattr(self, 'board'): self.board.deleteLater() self.ui.gridLayout.removeWidget(self.board) # Create a new game board with the specified size. self.board = QWidget() boardLayout = QGridLayout() # Set the initial player to blue self.currentPlayer = "blue" for row in range(self.boardSize): for col in range(self.boardSize): button = QPushButton() button.setMaximumSize(150, 150) boardLayout.addWidget(button, row, col) # Connect the clicked signal of the button to the buttonClicked function. button.clicked.connect(lambda _, r=row, c=col: self.buttonClicked(r, c)) self.board.setLayout(boardLayout) self.ui.gridLayout.addWidget(self.board) def buttonClicked(self, row, col): # Get the clicked button. button = self.board.layout().itemAtPosition(row, col).widget() # Set the mark for the current player. mark = "S" if self.currentPlayer == "blue" else "O" button.setText(mark) # Switch to the other player. self.currentPlayer = "red" if self.currentPlayer == "blue" else "blue" def setSize(self, size): # Update the size of the game board. self.boardSize = size self.createBoard() def setGameMode(self, mode): self.gameMode = mode if __name__ == '__main__': app = QApplication(sys.argv) game = SOSGame() game.show() sys.exit(app.exec_())
test_sos_game.py
from sos_game import SOSGame def test_create_board(): game = SOSGame() game.createBoard() assert game.board is not None assert game.board.layout().count() == game.boardSize ** 2 def test_button_clicked(): game = SOSGame() game.createBoard() button = game.board.layout().itemAtPosition(0, 0).widget() game.currentPlayer = "blue" game.buttonClicked(0, 0) assert button.text() == "S" assert game.currentPlayer == "red" def test_set_size(): game = SOSGame() game.setSize(4) assert game.boardSize == 4 game.createBoard() assert game.board.layout().count() == game.boardSize ** 2 def test_set_game_mode(): game = SOSGame() game.setGameMode("Simple") assert game.gameMode == "Simple"
解决方法
核心问题是Qt的UI组件必须在QApplication实例存在的环境下运行,测试代码直接创建SOSGame实例但未初始化QApplication,导致程序卡在UI初始化环节,Pytest无法继续执行断言和输出结果。
方法1:手动初始化QApplication
修改测试文件,在创建SOSGame实例前先初始化QApplication:
from sos_game import SOSGame from PyQt5.QtWidgets import QApplication import sys # 全局初始化QApplication,避免重复创建 app = QApplication.instance() or QApplication(sys.argv) def test_create_board(): game = SOSGame() game.createBoard() assert game.board is not None assert game.board.layout().count() == game.boardSize ** 2 def test_button_clicked(): game = SOSGame() game.createBoard() button = game.board.layout().itemAtPosition(0, 0).widget() game.currentPlayer = "blue" game.buttonClicked(0, 0) assert button.text() == "S" assert game.currentPlayer == "red" def test_set_size(): game = SOSGame() game.setSize(4) assert game.boardSize == 4 game.createBoard() assert game.board.layout().count() == game.boardSize ** 2 def test_set_game_mode(): game = SOSGame() game.setGameMode("Simple") assert game.gameMode == "Simple"
方法2:使用pytest-qt插件(专业Qt测试方案)
- 安装插件:
pip install pytest-qt
- 修改测试文件,用
qtbotfixture管理QApplication和事件循环:
from sos_game import SOSGame def test_create_board(qtbot): game = SOSGame() qtbot.addWidget(game) # 让qtbot管理UI组件 game.createBoard() assert game.board is not None assert game.board.layout().count() == game.boardSize ** 2 def test_button_clicked(qtbot): game = SOSGame() qtbot.addWidget(game) game.createBoard() button = game.board.layout().itemAtPosition(0, 0).widget() game.currentPlayer = "blue" game.buttonClicked(0, 0) assert button.text() == "S" assert game.currentPlayer == "red" def test_set_size(qtbot): game = SOSGame() qtbot.addWidget(game) game.setSize(4) assert game.boardSize == 4 game.createBoard() assert game.board.layout().count() == game.boardSize ** 2 def test_set_game_mode(): game = SOSGame() game.setGameMode("Simple") assert game.gameMode == "Simple"
该插件会自动处理QApplication创建和事件循环,还能模拟用户交互,适合复杂Qt UI测试。
方法3:解耦UI与业务逻辑(最佳实践)
若仅测试业务逻辑,可将核心逻辑从UI类中拆分,避免依赖Qt组件:
# 新建game_logic.py class SOSGameLogic: def __init__(self): self.boardSize = 3 self.currentPlayer = "blue" self.gameMode = "Simple" def create_board(self): # 返回棋盘数据结构,不涉及UI return [[None for _ in range(self.boardSize)] for _ in range(self.boardSize)] def button_clicked(self, row, col): mark = "S" if self.currentPlayer == "blue" else "O" self.currentPlayer = "red" if self.currentPlayer == "blue" else "blue" return mark def set_size(self, size): self.boardSize = size def set_game_mode(self, mode): self.gameMode = mode
针对该逻辑类编写测试,无需Qt环境,执行更快更稳定。
内容的提问来源于stack exchange,提问作者Donsickle
相关产品推荐
相关产品推荐

