4

I'm writing a functional test for the QGIS plugin I'm developing. There's a button in the plugin that is enabled only if there is a valid vector layer present. The thing I'm bumping into is the layer event handling from a standard lib unittest isn't triggering the button enable as expected. When I test manually, the button is enabled fine, but from the test it isn't.

My test setup is pretty straightforward:

import unittest

from qgis.core import QgsApplication, QgsVectorLayer

from namari_dockwidget import NamariDockWidget

app = QgsApplication(argv=[], GUIenabled=True) app.initQgis()

class NamariDockWidgetTest(unittest.TestCase): def setUp(self) -> None: self.dock_widget = NamariDockWidget()

def test_dockwidget_layer_selector(self) -> None:
    with self.subTest('When we start the widget, there is no layer set'):
        self.assertTrue(self.dock_widget.isEnabled())

        layer = self.dock_widget.mMapLayerComboBox.currentLayer()
        self.assertEqual(layer, None)

    with self.subTest('So the "Build model" button is disabled'):
        enabled = self.dock_widget.pushButtonBuildModel.isEnabled()
        self.assertFalse(enabled)

    with self.subTest('But when we load a vector data source'):
        layer = QgsVectorLayer(
            path='test/data/amersfoort-centre.gpkg',
            baseName='amersfoort-centre',
            providerLib='ogr')

        self.assertEqual(len(layer.fields()), 10)

        # Load the vector layer
        self.dock_widget.iface.addMapLayer(layer)

    with self.subTest('Then the build button is enabled'):
        enabled = self.dock_widget.pushButtonBuildModel.isEnabled()
        self.assertTrue(enabled)

However the last assertion fails: the button is not enabled once the layer is added through the iface object (that I learned from this excellent question). Any idea on what I'm missing?

To reproduce: the current state of the plugin is in https://github.com/reinvantveer/namari/tree/button_test_issue-alpha2. There's a very helpful Dockerile that can help you get up and running the test within minutes: just run docker build ., but there's also the output of the associated GitHub action build at https://github.com/reinvantveer/namari/runs/2208580233.

EDIT: I now see that I only loaded the UI elements from the NamariDockWidget, but this does not include the Namari class I wrote for the logic. Somehow, I need access to the QGIS iface object from within my unit test, but how does this work?

The plugin logic class begins like

# ...
class Namari:
    def __init__(self, iface: QgisInterface) -> None:

So a lot of the logic depends on the iface object being available. But I have currently no way of strapping a class instance to my test.

Rein
  • 51
  • 5
  • It appears I missed something obvious as well: the QGIS widget does not have an iface object either: https://github.com/reinvantveer/namari/runs/2208580233#step:3:176 but now I'm faced with the question how to enable this – Rein Apr 02 '21 at 12:56
  • This appears to be a tricky question: https://github.com/qgis/QGIS-Documentation/issues/3776 – Rein Apr 02 '21 at 14:40
  • Also related: https://gis.stackexchange.com/questions/380678/alternative-of-iface-for-standalone-pyqgis-application but no solution to this question – Rein Apr 02 '21 at 15:10

1 Answers1

1

Turns out this is an almost duplicate of this question, with an answer that put me on the right track.

The answer is also a lot more involved than I had imagined. So much more that I decided to write a post about it here.

The upshot: use the qgis_testrunner.sh script from the official QGIS docker image to run a Python test script containing a def run_all() function.

Rein
  • 51
  • 5