Automatisierte Tests für QGIS-Plugins schreiben?


16

Ich suche Ratschläge zum Schreiben automatischer Tests für in Python geschriebene QGIS-Plugins.

Ich habe in der Vergangenheit Tests für Python-Skripte mit PyUnit (dem unittestModul) geschrieben, aber noch nie für eine Anwendung mit einer grafischen Benutzeroberfläche . Ich habe eine Seite gefunden, auf der beschrieben wird, wie PyQt4.QTest für Komponententests mit Qt-Widgets verwendet wird ( http://www.voom.net/pyqt-qtest-example ), aber ich habe Probleme zu sehen, wie ich das verwenden kann mit einem Widget, das so entworfen wurde, dass es in QGIS ausgeführt werden kann.

Insbesondere fehlt der Abschnitt "Testen" in der PyQGIS-Dokumentation .

Was ich bisher habe ist:

  • Führen Sie die eigentliche Datenverarbeitung in isolierten Modulen oder Funktionen durch und schreiben Sie für diese Unit-Tests.
  • Führen Sie grundlegende Tests der Benutzeroberfläche mit QTest durch.
  • Beten Sie, dass alles zusammenhält, wenn Sie das Plugin in QGIS verwenden.

Gibt es einen besseren Weg?

Antworten:


11

Die Funktionen zum Testen von QGIS-Plugins (insbesondere die Frage des Integrationstests in einer QGIS-Umgebung, wie im OP hervorgehoben) wurden in letzter Zeit erheblich verbessert. Ich hoffe daher, dass dieses Update sowohl den zeitgenössischen Lesern als auch dem OP hilft.

Boundless veröffentlichte im Juli 2016 einen Artikel, der unbedingt gelesen werden muss, damit jeder, der es ernst meint, das Testen von QGIS-Plugins zu automatisieren, diesen Artikel lesen kann. QGIS Continuous Integration-Testumgebung für Python-Plugins . Es beschreibt den Ansatz und die Tools, die sie verwenden - allesamt Open Source. Schwerpunkte sind: -

  • Ihr spezieller QGIS-Plugin-Tester, der Tests innerhalb der QGIS-Umgebung automatisieren kann
  • Die Verwendung von Docker- QGIS-Images ermöglicht das Testen mit verschiedenen QGIS-Versionen / -Konfigurationen in einer containergestützten Umgebung
  • Ein spezielles Docker-QGIS-Image , das zum Testen von QGIS selbst verwendet wird, aber durch Aufrufen qgis_testrunner.shzum Ausführen von Komponententests für ein Plug-in verwendet werden kann
  • Die Verwendung von Travis CI für die kontinuierliche Integration - dh die vollständige Testsuite wird mit jedem neuen Code-Commit ausgeführt

Wenn Sie mit Travis CI / Docker vertraut sind, sollte die Einrichtung relativ einfach sein. Sie beschreiben die folgenden 4 Schritte und stellen 2 Beispiele für ihre eigenen Plugins bereit, die auf diese Weise eingerichtet wurden.

  1. Ziehen Sie das Docker-Image mit der QGIS-Testumgebung und führen Sie es aus
  2. Führen Sie qgis_setup.sh NameOfYourPlugin aus, um das Plugin zu installieren und QGIS für den Testläufer vorzubereiten
  3. Führen Sie optional alle Vorgänge aus, die zum Erstellen Ihres Plugins erforderlich sind
  4. Führen Sie den Test-Runner im Docker aus und rufen Sie die qgis_testrunner.sh

Sie haben nach Best Practice gefragt und ab heute würde ich dies mit Sicherheit in Betracht ziehen. QGIS-Dokumente haben noch keinen eigenen Abschnitt zum Testen von Plugins (ich gehe davon aus, dass sich dies in Kürze ändern wird), aber der Ansatz "Bete, dass alles zusammenhält" ist sicherlich nicht mehr die einzige Option.


4
Grenzenlos ist nicht mehr. Hat jemand diesen Inhalt gespeichert?
Pedro Camargo

8

Es sieht so aus, als ob dies unittestzum Testen von Python-Plugins verwendet werden kann, die in eine eigenständige Python-Anwendung geladen wurden .

qgis.core.iface ist in eigenständigen Anwendungen nicht verfügbar, daher habe ich eine Dummy-Instanz geschrieben, die eine Funktion zurückgibt, die Argumente akzeptiert und sonst nichts unternimmt. Dies bedeutet, dass Anrufe wie self.iface.addToolBarIcon(self.action)keine Fehler werfen.

Im folgenden Beispiel wird ein Plugin geladen myplugin, das einige Dropdown-Menüs mit Ebenennamen aus der Kartenebenenregistrierung enthält. Die Tests prüfen, ob die Menüs korrekt ausgefüllt wurden und mit denen interagiert werden kann. Ich bin nicht sicher, ob dies der beste Weg ist, um das Plugin zu laden, aber es scheint zu funktionieren.

myplugin widget

#!/usr/bin/env python

import unittest

import os
import sys

# configure python to play nicely with qgis
osgeo4w_root = r'C:/OSGeo4W'
os.environ['PATH'] = '{}/bin{}{}'.format(osgeo4w_root, os.pathsep, os.environ['PATH'])
sys.path.insert(0, '{}/apps/qgis/python'.format(osgeo4w_root))
sys.path.insert(1, '{}/apps/python27/lib/site-packages'.format(osgeo4w_root))

# import Qt
from PyQt4 import QtCore, QtGui, QtTest
from PyQt4.QtCore import Qt

# import PyQGIS
from qgis.core import *
from qgis.gui import *

# disable debug messages
os.environ['QGIS_DEBUG'] = '-1'

def setUpModule():
    # load qgis providers
    QgsApplication.setPrefixPath('{}/apps/qgis'.format(osgeo4w_root), True)
    QgsApplication.initQgis()

    globals()['shapefile_path'] = 'D:/MasterMap.shp'

# FIXME: this seems to throw errors
#def tearDownModule():
#    QgsApplication.exitQgis()

# dummy instance to replace qgis.utils.iface
class QgisInterfaceDummy(object):
    def __getattr__(self, name):
        # return an function that accepts any arguments and does nothing
        def dummy(*args, **kwargs):
            return None
        return dummy

class ExamplePluginTest(unittest.TestCase):
    def setUp(self):
        # create a new application instance
        self.app = app = QtGui.QApplication(sys.argv)

        # create a map canvas widget
        self.canvas = canvas = QgsMapCanvas()
        canvas.setCanvasColor(QtGui.QColor('white'))
        canvas.enableAntiAliasing(True)

        # load a shapefile
        layer = QgsVectorLayer(shapefile_path, 'MasterMap', 'ogr')

        # add the layer to the canvas and zoom to it
        QgsMapLayerRegistry.instance().addMapLayer(layer)
        canvas.setLayerSet([QgsMapCanvasLayer(layer)])
        canvas.setExtent(layer.extent())

        # display the map canvas widget
        #canvas.show()

        iface = QgisInterfaceDummy()

        # import the plugin to be tested
        import myplugin
        self.plugin = myplugin.classFactory(iface)
        self.plugin.initGui()
        self.dlg = self.plugin.dlg
        #self.dlg.show()

    def test_populated(self):
        '''Are the combo boxes populated correctly?'''
        self.assertEqual(self.dlg.ui.comboBox_raster.currentText(), '')
        self.assertEqual(self.dlg.ui.comboBox_vector.currentText(), 'MasterMap')
        self.assertEqual(self.dlg.ui.comboBox_all1.currentText(), '')
        self.dlg.ui.comboBox_all1.setCurrentIndex(1)
        self.assertEqual(self.dlg.ui.comboBox_all1.currentText(), 'MasterMap')

    def test_dlg_name(self):
        self.assertEqual(self.dlg.windowTitle(), 'Testing')

    def test_click_widget(self):
        '''The OK button should close the dialog'''
        self.dlg.show()
        self.assertEqual(self.dlg.isVisible(), True)
        okWidget = self.dlg.ui.buttonBox.button(self.dlg.ui.buttonBox.Ok)
        QtTest.QTest.mouseClick(okWidget, Qt.LeftButton)
        self.assertEqual(self.dlg.isVisible(), False)

    def tearDown(self):
        self.plugin.unload()
        del(self.plugin)
        del(self.app) # do not forget this

if __name__ == "__main__":
    unittest.main()

4
Ich habe seitdem einen Artikel basierend auf dieser Antwort hier geschrieben: snorf.net/blog/2014/01/04/…
Snorfalorpagus

3

Ich habe auch ein DummyInterface zusammengestellt, mit dem Sie eigenständige QGIS-Plugins testen können. Nachdem Sie den Snorfalorpagus-Blog gelesen haben, lesen Sie meine Antwort hier .

Um ein Beispiel aus der Praxis, wie ich Test (ed) QGIS-Plugins finden Sie auf dieser GitHub Projekt https://github.com/UdK-VPT/Open_eQuarter/tree/master/mole und einen Blick in die haben Tests - Paket.


-1

Dies könnte helfen: Testen Sie PyQt-GUIs mit QTest und unittest http://www.voom.net/pyqt-qtest-example


1
Das ist die "diese Seite", auf die in der Frage verwiesen wird (zugegebenermaßen nicht zu deutlich). Mein Problem ist, wie teste ich eine Schnittstelle, die für die Ausführung mit Kombinationsfeldern ausgelegt ist, die in QGIS mit Ebenen gefüllt sind.
Snorfalorpagus
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.