23 votos

Redacción de pruebas automatizadas para plugins de QGIS

Estoy buscando consejo sobre cómo escribir pruebas automáticas para plugins de QGIS escritos en Python.

He escrito pruebas para scripts de Python en el pasado usando PyUnit (la aplicación unittest ), pero nunca lo he hecho para una aplicación con interfaz gráfica de usuario. He encontrado una página que describe cómo utilizar PyQt4.QTest para realizar pruebas unitarias en widgets Qt ( http://www.voom.net/pyqt-qtest-example ), pero estoy luchando para ver cómo puedo usar esto con un widget que ha sido diseñado para ejecutarse desde dentro de QGIS.

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

Lo que tengo hasta ahora es:

  • Mantenga el procesamiento real de los datos en módulos o funciones aislados, y escriba pruebas unitarias para ellos;
  • Realizar pruebas básicas de la interfaz de usuario utilizando QTest ;
  • Reza para que todo encaje cuando utilices el plugin desde QGIS.

¿Hay alguna forma mejor?

17voto

MatzFan Puntos 170

Las capacidades para probar plugins de QGIS (en particular 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 ayudará a los lectores contemporáneos, así como el OP.

Sin límites publicó un artículo de lectura obligada en julio de 2016 para cualquiera que se tome en serio la automatización de las pruebas de los plugins de QGIS titulados; Entorno de pruebas de integración continua de QGIS para plugins de Python . Describe el enfoque y las herramientas que utilizan, todas ellas de código abierto.

Los aspectos clave son:

  • Su especial Probador de plugins de QGIS que puede automatizar las pruebas en el entorno QGIS
  • El uso de docker Imágenes de QGIS, que permiten realizar pruebas con varias versiones/configuraciones de QGIS en un entorno basado en contenedores.
  • A imagen especial docker QGIS que se utiliza para probar el propio QGIS, pero que -al invocar a qgis_testrunner.sh se puede utilizar para ejecutar pruebas unitarias en un plugin
  • El uso de Travis CI para la integración continua, es decir, el conjunto completo de pruebas se ejecuta con cada nueva confirmación de código.

Si estás familiarizado con Travis CI/docker debería ser relativamente fácil de configurar.

  1. Extrae la imagen Docker con el entorno de pruebas de QGIS y ejecútala
  2. Ejecute qgis_setup.sh NameOfYourPlugin para instalar el plugin y preparar QGIS para el test runner
  3. Opcionalmente realizar todas las operaciones necesarias para construir su plugin
  4. Ejecutar el test runner dentro del Docker invocando el comando qgis_testrunner.sh

Pidió las mejores prácticas y, a día de hoy, sin duda las considero así. QGIS docs todavía no tienen una sección dedicada a la prueba de plugins (Espero que esto cambie en breve), pero el "Ore para que todo se mantiene unido" enfoque es, sin duda ya no es la única opción.

ACTUALIZACIÓN (abril-2020): Algunos de los enlaces mencionados ya no funcionan, pero se proporciona un pequeño ejemplo de cómo ejecutar las pruebas utilizando Travis CI aquí junto con el qgis-testing environment Dockerfile de Planeta anteriormente conocido como Sin límites .

9voto

Fitzcarraldo Puntos 423

Parece que es posible utilizar unittest para probar plugins de Python cargados en un archivo aplicación Python independiente .

qgis.core.iface no está disponible desde aplicaciones independientes, así que he escrito 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 plugin myplugin que tiene algunos menús desplegables con nombres de capas tomados del registro de capas de mapas. Las pruebas comprueban si los menús se han rellenado correctamente y se puede interactuar con ellos. No estoy seguro de si esta es la mejor manera de cargar el plugin, pero parece que funciona.

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()

5voto

mjk Puntos 88

La respuesta aceptada ha quedado obsoleta. En mi opinión, obtener una imagen Docker en ejecución con fines de prueba es la mejor manera de proceder. Instrucciones en el repositorio oficial de QGIS ( Imagen docker de QGIS ) es autosuficiente, y explica en detalle cómo poner en marcha pruebas locales y pruebas automatizadas . La buena gente de OPENGIS.ch también hacen un gran trabajo proporcionando una guía sobre cómo realizar pruebas unitarias utilizando la imagen docker oficial .

En lo que yo personalmente estaba atascado era en la estructura de directorios que se requiere para CI/unit-testing. El instrucciones hablar de la estructura de directorios del directorio de pruebas. He añadido el resto de la estructura del proyecto que también es necesario (que no era obvio para mí, y espero que ayude a otros que se atreven a pisar estos caminos traicioneros):

/Project/
├── PluginDirectory/ (This directory gets deployed as your actual plugin)
|   ├── __init__.py
|   └──"Rest of your Code"
└── tests/
    ├── test_thatthing.py
    └── test_thatotherthing.py

Ahora bien tests se puede montar como /tests_directory/ mientras se ejecuta la imagen docker, como tal:

$ docker run -d --name qgis -v /tmp/.X11-unix:/tmp/.X11-unix \
    -v /tests/:/tests_directory \
    -e DISPLAY=:99 \
    qgis/qgis:latest

4voto

user35978 Puntos 1187

También he creado una DummyInterface, que te permite probar los plugins de QGIS de forma independiente. Después de leer Snorfalorpagus blog, echa un vistazo a mi respuesta aquí .

Para ver un ejemplo real de cómo pruebo los plugins de QGIS, visita este proyecto de github en https://github.com/UdK-VPT/Open_eQuarter/tree/master/mole y eche un vistazo al pruebas -paquete.

-1voto

Hassan Puntos 11

Esto podría ayudar: Probar GUIs PyQt con QTest y unittest http://www.voom.net/pyqt-qtest-example

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X