QGIS 플러그인에 대한 자동화 된 테스트를 작성하고 있습니까?


16

파이썬으로 작성된 QGIS 플러그인에 대한 자동 테스트 작성에 대한 조언을 찾고 있습니다.

PyUnit ( unittest모듈)을 사용하여 과거에 Python 스크립트에 대한 테스트를 작성 했지만 GUI가있는 응용 프로그램에는 테스트를 수행하지 않았습니다. PyQt4.QTest를 사용하여 Qt 위젯에서 단위 테스트를 수행하는 방법을 설명하는 페이지를 찾았 지만 ( http://www.voom.net/pyqt-qtest-example ) 어떻게 사용할 수 있는지 고심하고 있습니다. QGIS 내에서 실행되도록 설계된 위젯이 있습니다.

PyQGIS 문서 의 "테스트"섹션 은 특히 ​​없습니다.

내가 지금까지 가지고있는 것은 :

  • 데이터의 실제 처리를 격리 된 모듈 또는 함수로 유지하고 이에 대한 단위 테스트를 작성하십시오.
  • QTest를 사용하여 UI의 기본 테스트를 수행하십시오.
  • QGIS 내에서 플러그인을 사용할 때 모두 함께 유지되도록기도하십시오.

더 좋은 방법이 있습니까?

답변:


11

QGIS 플러그인 테스트 기능 (특히 OP가 강조하는 QGIS 환경 내 통합 테스트 문제)이 최근 크게 개선되었습니다. 따라서이 업데이트가 최신 독자뿐만 아니라 OP에도 도움이 되길 바랍니다.

Boundless 는 2016 년 7 월 QGIS 플러그인 테스트 자동화에 대해 진지한 사용자를 위해 반드시 읽어야 할 기사를 게시했습니다. Python 플러그인을위한 QGIS Continuous Integration 테스트 환경 . 여기에는 이들이 사용하는 접근 방식과 도구가 설명되어 있으며 모두 오픈 소스입니다. 주요 측면은 다음과 같습니다.

  • QGIS 환경 에서 테스트를 자동화 할 수있는 특수한 QGIS 플러그인 테스터
  • 컨테이너 기반 환경에서 다양한 QGIS 버전 / 구성에 대해 테스트 할 수있는 docker QGIS 이미지 사용
  • 특별한 고정 표시기의 QGIS 이미지 QGIS 자체를 테스트하기 위해 사용되는,하지만 어느 - 호출하여이 qgis_testrunner.sh플러그인에 단위 테스트를 실행하는 데 사용할 수 있습니다
  • 지속적인 통합을 위해 Travis CI 를 사용합니다. 즉 전체 테스트 스위트는 새로운 코드 커밋마다 실행됩니다.

Travis CI / docker에 익숙하다면 비교적 쉽게 설정할 수 있어야합니다. 다음 4 단계를 설명하고 이러한 방식으로 설정된 자체 플러그인의 2 가지 예를 제공합니다.

  1. QGIS 테스트 환경에서 Docker 이미지를 가져 와서 실행하십시오.
  2. qgis_setup.sh NameOfYourPlugin을 실행하여 플러그인을 설치하고 테스트 실행자를위한 QGIS를 준비하십시오.
  3. 선택적으로 플러그인 빌드에 필요한 모든 작업을 수행
  4. Docker 내부에서 테스트 러너를 실행하여 qgis_testrunner.sh

당신은 모범 사례를 요청했습니다 & 오늘 기준으로 나는 분명히 이것을 고려할 것입니다. QGIS 문서는 여전히 플러그인 테스트에 대한 전용 섹션을 가지고 있지 않지만 (이것은 곧 바뀔 것으로 예상됩니다) "모든 것이 함께 유지되도록기도하십시오"접근 방식이 더 이상 유일한 옵션은 아닙니다.


4
무한은 더 이상 없습니다. 그 내용을 저장 한 사람이 있습니까?
페드로 마르고

8

독립 실행 형 Python 응용 프로그램에unittest 로드 된 Python 플러그인을 테스트하는 데 사용할 수있는 것 같습니다 .

qgis.core.iface는 독립형 응용 프로그램에서 사용할 수 없으므로 주어진 인수를 허용하고 다른 작업을 수행하지 않는 함수를 반환하는 더미 인스턴스를 작성했습니다. 즉, 같은 호출은 self.iface.addToolBarIcon(self.action)오류를 발생시키지 않습니다.

아래 예제는 plugin을로드합니다 myplugin. 여기에는 맵 레이어 레지스트리에서 가져온 레이어 이름이있는 드롭 다운 메뉴가 있습니다. 테스트는 메뉴가 올바르게 채워져 있고 상호 작용할 수 있는지 확인합니다. 이것이 플러그인을로드하는 가장 좋은 방법인지 확실하지 않지만 작동하는 것 같습니다.

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
나는이 답변에 기초한 기사를 여기에 썼습니다
Snorfalorpagus

3

또한 Qummy 플러그인을 독립형으로 테스트 할 수있는 DummyInterface도 함께 제공했습니다. Snorfalorpagus 블로그를 읽은 후 여기 에서 내 답변을 확인 하십시오 .

실생활 예제를 찾으려면, 내가 시험 (ED) QGIS - 플러그인에서이 GitHub의 프로젝트를 방문하는 방법에 https://github.com/UdK-VPT/Open_eQuarter/tree/master/mole을 과에보고가 테스트를 - 꾸러미.


-1

QTest 및 unittest를 사용하여 PyQt GUI 테스트 http://www.voom.net/pyqt-qtest-example


1
그것은 질문에 링크 된 "이 페이지"입니다 (물론 명확하지는 않습니다). 내 문제는 QGIS의 레이어로 채워진 콤보 상자와 같은 항목으로 실행되도록 설계된 인터페이스를 어떻게 테스트합니까?
Snorfalorpagus
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.