[Edit 9/12/2023 added 'xvfb-run' to 'test.sh' as suggested here, but still pytest still fails with the same seg fault.]
I'm getting a segmentation fault when unit testing PyQT6 app with GitHub Actions, and pytest-qt.
Here in my dummy repo, I have .github/workflows/test.yml as follows:
name: unit-tests
run-name: Run unit tests after push by @${{ github.actor }}
on:
push:
branches: [ master ]
jobs:
unit-test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os : [ubuntu-latest]
python-version: [ "3.9" ]
env:
DISPLAY: ':99.0'
steps:
- uses: actions/checkout@v3
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4
with:
python-version: ${{ matrix.python-version }}
- name: Install dependencies
run: |
sudo apt install libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 x11-utils libegl1 xvfb qt6-base-dev
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1920x1200x24 -ac +extension GLX
pip install --upgrade pip
sudo pip install -r requirements.txt
- name: Test with pytest
run: |
sudo chmod +x ./test.sh
sudo -E xvfb-run --auto-servernum ./test.sh
I'm using the the GitHub Action configuration suggested by pytest-qt's documentation.
Here's my install dependencies step:
sudo apt install libxkbcommon-x11-0 libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 libxcb-render-util0 libxcb-xinerama0 libxcb-xfixes0 x11-utils libegl1
/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -screen 0 1920x1200x24 -ac +extension GLX
sudo apt install qt6-base-dev
pip install -r requirements.txt
The first two lines comes from the pytest-qt's documentation as mentioned before. When that didn't work out, I added sudo apt install qt6-base-dev as suggested by one of the answers here.
The test.sh simply runs pytest DummyTest.py.
DummyTest.py is a simple PyQT example:
import sys
import pytest
from PyQt6 import QtCore, QtWidgets
from PyQt6.QtWidgets import QMainWindow, QPushButton
# Import your application module here
# from your_app_module import YourMainWindow
# A dummy PyQt application for testing
class DummyApp(QMainWindow):
def __init__(self):
super().__init__()
self.button = QPushButton("Click me", self)
self.button.clicked.connect(self.on_button_click)
def on_button_click(self):
self.button.setText("Clicked!")
@pytest.fixture
def app(qtbot):
# Create a QApplication instance for testing
test_app = QtWidgets.QApplication(sys.argv)
# Create a dummy application window and show it
window = DummyApp()
window.show()
# QtBot is used to simulate user actions
qtbot.addWidget(window)
yield window
# Clean up after the test
window.close()
def test_button_click(app, qtbot):
# faulthandler.disable()
# Simulate a button click
qtbot.mouseClick(app.button, QtCore.Qt.MouseButton.LeftButton)
# Assert that the button text changes as expected
assert app.button.text() == "Clicked!"
pytest DummyTest.py runs fine on my local computer.
But as you can see here on the failed GitHub jobs. It fails with a segmentation fault.
============================= test session starts ==============================
platform linux -- Python 3.9.18, pytest-7.4.2, pluggy-1.3.0
PyQt6 6.5.2 -- Qt runtime 6.5.2 -- Qt compiled 6.5.2
rootdir: /home/runner/work/Qt6TestApp/Qt6TestApp
plugins: qt-4.2.0
collected 1 item
Fatal Python error: Aborted
Current thread 0x00007f6298f03b80 (most recent call first):
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pytestqt/plugin.py", line 66 in qapp
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/fixtures.py", line 902 in call_fixture_func
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/fixtures.py", line 1123 in pytest_fixture_setup
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_callers.py", line 77 in _multicall
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_manager.py", line 115 in _hookexec
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_hooks.py", line 493 in __call__
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/fixtures.py", line 1069 in execute
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/fixtures.py", line 693 in _compute_fixture_value
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/fixtures.py", line 607 in _get_active_fixturedef
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/fixtures.py", line 585 in getfixturevalue
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/fixtures.py", line 566 in _fillfixtures
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/python.py", line 1795 in setup
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/runner.py", line 494 in setup
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/runner.py", line 157 in pytest_runtest_setup
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_callers.py", line 77 in _multicall
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_manager.py", line 115 in _hookexec
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_hooks.py", line 493 in __call__
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/runner.py", line 262 in <lambda>
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/runner.py", line 341 in from_call
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/runner.py", line 261 in call_runtest_hook
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/runner.py", line 222 in call_and_report
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/runner.py", line 127 in runtestprotocol
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/runner.py", line 114 in pytest_runtest_protocol
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_callers.py", line 77 in _multicall
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_manager.py", line 115 in _hookexec
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_hooks.py", line 493 in __call__
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/main.py", line 350 in pytest_runtestloop
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_callers.py", line 77 in _multicall
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_manager.py", line 115 in _hookexec
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_hooks.py", line 493 in __call__
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/main.py", line 325 in _main
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/main.py", line 271 in wrap_session
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/main.py", line 318 in pytest_cmdline_main
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_callers.py", line 77 in _multicall
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_manager.py", line 115 in _hookexec
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/pluggy/_hooks.py", line 493 in __call__
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/config/__init__.py", line 169 in main
File "/opt/hostedtoolcache/Python/3.9.18/x64/lib/python3.9/site-packages/_pytest/config/__init__.py", line 192 in console_main
File "/opt/hostedtoolcache/Python/3.9.18/x64/bin/pytest", line 8 in <module>
./test.sh: line 1: 2529 Aborted (core dumped) pytest DummyTest.py
DummyTest.py
Error: Process completed with exit code 134.
Without be able to run this simple example, it almost feel like GitHub runners lacks support for testing PyQt apps at this point... Could anyone spot what might be missing here?