GispoCoding / pytest-qgis

A pytest plugin for testing QGIS python plugins
GNU General Public License v2.0
29 stars 8 forks source link

qgis.utils iface isn't being replaced #35

Closed kaiguy23 closed 1 year ago

kaiguy23 commented 1 year ago

I have created a plugin using qgis 3.28.4. My plugin occasionally will make the following call from qgis.utils import iface. In the testing docker container, the iface imported from qgis.utils is None, rather than an actual iface object.

In your README, it claims that pytest_configure hook is used to initialize and configure [QgsApplication](https://qgis.org/pyqgis/master/core/QgsApplication.html). With QGIS >= 3.18 it is also used to patch qgis.utils.iface with qgis_iface automatically. However, that doesn't seem to be the case.

Am I supposed to be using this pytest_configure somewhere in my test case or in my conftest.py file?

Thanks

Joonalai commented 1 year ago

Thank you for the issue and for using pytest-qgis!

I think that what is happening here is that you are importing the module that has from qgis.utils import iface in conftest.py. This makes the pytest-qgis patch the qgis.utils.iface after it has already been imported. The solution is to avoid importing those modules (or other modules that are importing those modules etc.) in root of conftest.py but rather in fixtures. In test modules the modules can be imported as usual, the problem is only in conftest files.

Here are a example of the problem:

module_a.py:

from qgis.utils import iface

class Myclass:
...

conftest.py:

from module_a import MyClass # This line causes the iface not to be patched in this module

@pytest.fixture()
def my_class():
    return MyClass()
...

Solution is to import module_a in a fixture:

conftest.py:

@pytest.fixture()
def my_class():
    from module_a import MyClass # Now iface is already patched by the pytest_configure hook of pytest-qgis
    return MyClass()
...

Hopefully this helps.

kaiguy23 commented 1 year ago

Thanks for quick reply! I’ll give this a shot tomorrow and let you know if it resolves my issue.

kaiguy23 commented 1 year ago

On another note, I was recently using the pytest-qt module to simulate mouse clicks on a QComboBox in my plugin. I was trying to use their qtbot’s keyClicks to try and change the combo box text.

For some reason, this seems to work 50% of the time. I have 4 items in my combo box (aspen, bot, bot_train, bot_test) and for some reason the combo box text changes for aspen and bot but not for bot_train and bot_test. I have never seen the combo box fail to switch when I use the plugin myself; this seems to only occur in the test environment.

I saw that you guys have a qgis_bot fixture, but it doesn’t seem to have this keyClicks attribute. Should I be using this module instead, and if so, how should I be using it?

Any advice would be appreciated! This might be a pytest-qt problem, but I figured I should ask here since I am testing a qgis plugin. Thanks!

Joonalai commented 1 year ago

Edit: replied to the new issue.

nicoddemus commented 1 year ago

Hi, pytest-qt maintainer here.

On another note, I was recently using the pytest-qt module to simulate mouse clicks on a QComboBox in my plugin. I was trying to use their qtbot’s keyClicks to try and change the combo box text.

In general, prefer to interact with widgets using their direct methods, rather than QtBot's: calling combo.setCurrentIndex will call the connected signal as expected and will work much more reliably than trying to simulate user's clicks.

I realize our documentation needs to be updated on that recommendation (EDIT: https://github.com/pytest-dev/pytest-qt/pull/493).

kaiguy23 commented 1 year ago

Thanks for all the help! Importing my plugin within the fixture solves the iface issue. As for the pytest-qt qtbot, I will just use the setCurrentIndex method.

Joonalai commented 1 year ago

Great to hear! I added commit to mention about the issue in the PR #34.