You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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测试方案)

  1. 安装插件:
pip install pytest-qt
  1. 修改测试文件,用qtbot fixture管理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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 20:00:05