¿Escribir pruebas automatizadas para complementos QGIS?

16

Estoy buscando consejos sobre cómo escribir pruebas automáticas para complementos QGIS escritos en Python.

He escrito pruebas para scripts de Python en el pasado usando PyUnit (el unittestmódulo), pero nunca lo he hecho para una aplicación con una GUI. Encontré una página que describe cómo usar PyQt4.QTest para hacer pruebas unitarias en widgets Qt ( http://www.voom.net/pyqt-qtest-example ), pero me cuesta ver cómo puedo usar esto con un widget diseñado para ejecutarse desde QGIS.

La sección sobre "Pruebas" en la documentación de PyQGIS está notablemente ausente.

Lo que tengo hasta ahora es:

  • Mantenga el procesamiento real de datos en módulos o funciones aisladas, y escriba pruebas unitarias para ellos;
  • Realizar pruebas básicas de la interfaz de usuario con QTest;
  • Ore para que todo se mantenga unido cuando use el complemento desde QGIS.

¿Hay una mejor manera?

Snorfalorpagus
fuente

Respuestas:

11

Las capacidades para probar los complementos QGIS (particularmente la cuestión de las pruebas de integración, dentro de un entorno QGIS, como destaca el OP) han mejorado mucho recientemente. Por lo tanto, espero que esta actualización ayude a los lectores contemporáneos, así como a la OP.

Boundless publicó un artículo de lectura obligatoria en julio de 2016 para cualquier persona seria sobre la automatización de las pruebas de los complementos QGIS titulados; Entorno de prueba de integración continua QGIS para complementos de Python . Describe el enfoque y las herramientas que utilizan, todos los cuales son de código abierto. Los aspectos clave son: -

  • Su probador especial de complementos QGIS que puede automatizar las pruebas dentro del entorno QGIS
  • El uso de imágenes QGIS de Docker , lo que permite realizar pruebas contra diversas versiones / configuraciones de QGIS en un entorno basado en contenedores
  • Una imagen especial de Docker QGIS , que se usa para probar QGIS en sí, pero que, al invocar, qgis_testrunner.shse puede usar para ejecutar pruebas unitarias en un complemento
  • El uso de Travis CI para la integración continua, es decir, el conjunto de pruebas completo se ejecuta con cada nueva confirmación de código

Si está familiarizado con Travis CI / docker, debería ser relativamente fácil de configurar. Describen los siguientes 4 pasos y proporcionan 2 ejemplos de sus propios complementos configurados de esta manera.

  1. Tire de la imagen de Docker con el entorno de prueba QGIS y ejecútelo
  2. Ejecute qgis_setup.sh NameOfYourPlugin para instalar el complemento y preparar QGIS para el corredor de prueba
  3. Opcionalmente, realice todas las operaciones necesarias para construir su complemento
  4. Ejecute el corredor de prueba dentro del Docker invocando el qgis_testrunner.sh

Usted solicitó las mejores prácticas y a partir de hoy ciertamente lo consideraría. Los documentos de QGIS todavía no tienen una sección dedicada a las pruebas de complementos (espero que esto cambie en breve), pero el enfoque "Orar para que todo se mantenga unido" ya no es la única opción.

MatzFan
fuente
44
Ilimitado ya no existe. ¿Alguien ha guardado ese contenido?
Pedro Camargo el
8

Parece que esto es posible de usar unittestpara probar los complementos de Python cargados en una aplicación de Python independiente .

qgis.core.iface no está disponible en aplicaciones independientes, por lo que escribí una instancia ficticia que devuelve una función que aceptará cualquier argumento que se le dé y no hará nada más. Esto significa que las llamadas como self.iface.addToolBarIcon(self.action)no arrojan errores.

El siguiente ejemplo carga un complemento myplugin, que tiene algunos menús desplegables con nombres de capa tomados del registro de la capa del mapa. Las pruebas verifican si los menús se han llenado correctamente y si se puede interactuar con ellos. No estoy seguro de si esta es la mejor manera de cargar el complemento, pero parece funcionar.

widget de 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()
Snorfalorpagus
fuente
44
Desde entonces escribí un artículo basado en esta respuesta aquí: snorf.net/blog/2014/01/04/…
Snorfalorpagus
3

También he creado un DummyInterface, que le permite probar los complementos QGIS de forma independiente. Después de leer el blog de Snorfalorpagus, mira mi respuesta aquí .

Para encontrar un ejemplo de la vida real, sobre cómo pruebo (ed) los complementos QGIS, visite este proyecto github en https://github.com/UdK-VPT/Open_eQuarter/tree/master/mole y eche un vistazo a las pruebas : paquete.

Kim
fuente
-1

Esto podría ayudar: Pruebe las GUI de PyQt con QTest y unittest http://www.voom.net/pyqt-qtest-example

Stefan
fuente
1
Esa es la "esta página" vinculada a la pregunta (ciertamente no demasiado clara). Mi problema es cómo pruebo una interfaz que está diseñada para ejecutarse con elementos como cuadros combinados con capas en QGIS.
Snorfalorpagus