Scrivere test automatizzati per i plugin QGIS?


16

Sto cercando consigli su come scrivere test automatici per plugin QGIS scritti in Python.

Ho scritto test per gli script Python in passato usando PyUnit (il unittestmodulo), ma non l'ho mai fatto per un'applicazione con una GUI. Ho trovato una pagina che descrive come utilizzare PyQt4.QTest per eseguire unit test sui widget Qt ( http://www.voom.net/pyqt-qtest-example ), ma faccio fatica a vedere come posso usare questo con un widget progettato per essere eseguito da QGIS.

La sezione "Test" nella documentazione di PyQGIS è assente.

Quello che ho finora è:

  • Mantenere l'elaborazione effettiva dei dati in moduli o funzioni isolati e scrivere test unitari per quelli;
  • Eseguire test di base dell'interfaccia utente utilizzando QTest;
  • Prega che tutto funzioni insieme quando usi il plugin da QGIS.

C'è un modo migliore?

Risposte:


11

Le funzionalità per testare i plug-in QGIS (in particolare la questione dei test di integrazione, in un ambiente QGIS, come evidenziato dall'OP) sono migliorate molto di recente. Spero quindi che questo aggiornamento aiuti i lettori contemporanei, così come l'OP.

Boundless ha pubblicato un articolo da leggere a luglio 2016 per chiunque sia seriamente intenzionato ad automatizzare i test dei plugin QGIS intitolati; Ambiente di test di integrazione continua QGIS per plugin Python . Descrive l'approccio e gli strumenti che usano, tutti open source. Gli aspetti chiave sono: -

  • Il loro speciale tester per plugin QGIS che può automatizzare i test all'interno dell'ambiente QGIS
  • L'uso di immagini docking QGIS, che consente di eseguire test su varie versioni / configurazioni QGIS in un ambiente container-base
  • Un'immagine QGIS docker speciale , utilizzata per testare QGIS stesso, ma che, invocando, qgis_testrunner.shpuò essere utilizzata per eseguire unit test su un plugin
  • L'uso di Travis CI per l'integrazione continua, ovvero la suite di test completa viene eseguita con ogni nuovo commit del codice

Se hai familiarità con Travis CI / docker, dovrebbe essere relativamente facile da configurare. Descrivono i seguenti 4 passaggi e forniscono 2 esempi dei propri plugin impostati in questo modo.

  1. Estrarre l'immagine Docker con l'ambiente di test QGIS ed eseguirla
  2. Esegui qgis_setup.sh NameOfYourPlugin per installare il plug-in e preparare QGIS per il test runner
  3. Facoltativamente, esegui tutte le operazioni necessarie per creare il tuo plug-in
  4. Esegui il test runner all'interno della Docker invocando il qgis_testrunner.sh

Hai chiesto le migliori pratiche e da oggi lo prenderei sicuramente in considerazione. I documenti di QGIS non hanno ancora una sezione dedicata ai test dei plugin (mi aspetto che questo cambi a breve) ma l'approccio "Prega che tutto tenga insieme" non è certamente l'unica opzione.


4
Boundless non esiste più. Qualcuno ha salvato quel contenuto?
Pedro Camargo,

8

Sembra che sia possibile utilizzarlo unittestper testare i plugin Python caricati in un'applicazione Python autonoma .

qgis.core.iface non è disponibile da applicazioni autonome, quindi ho scritto un'istanza fittizia che restituisce una funzione che accetterà qualsiasi argomento dato ad essa e non farà altro. Ciò significa che chiamate come self.iface.addToolBarIcon(self.action)non generano errori.

L'esempio seguente carica un plug-in myplugin, che presenta alcuni menu a discesa con nomi di layer presi dal registro dei layer della mappa. I test controllano se i menu sono stati compilati correttamente e possono essere interagiti. Non sono sicuro che questo sia il modo migliore per caricare il plugin, ma sembra funzionare.

widget di myplugin

#!/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
Da allora ho scritto un articolo basato su questa risposta qui: snorf.net/blog/2014/01/04/…
Snorfalorpagus

3

Ho anche messo insieme un DummyInterface, che ti consente di testare i plugin QGIS autonomamente. Dopo aver letto il blog di Snorfalorpagus, controlla qui la mia risposta .

Per trovare un esempio di vita reale, su come testare (ed) i plug-in QGIS visitare questo progetto github su https://github.com/UdK-VPT/Open_eQuarter/tree/master/mole e dare un'occhiata ai test - pacchetto.


-1

Questo potrebbe aiutare: testare le GUI di PyQt con QTest e unittest http://www.voom.net/pyqt-qtest-example


1
Questa è la "questa pagina" collegata alla domanda (certamente non troppo chiaramente). Il mio problema è, come testare un'interfaccia progettata per funzionare con cose come caselle combinate popolate con livelli in QGIS.
Snorfalorpagus,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.