Viết bài kiểm tra tự động cho các plugin QGIS?


16

Tôi đang tìm kiếm lời khuyên về việc viết các bài kiểm tra tự động cho các plugin QGIS được viết bằng Python.

Tôi đã viết các bài kiểm tra cho các tập lệnh Python trong quá khứ bằng PyUnit ( unittestmô-đun), nhưng chưa bao giờ làm như vậy cho một ứng dụng có GUI. Tôi đã tìm thấy một trang mô tả cách sử dụng PyQt4.QTest để thực hiện kiểm tra đơn vị trên các tiện ích Qt ( http://www.voom.net/pyqt-qtest-example ), nhưng tôi đang cố gắng xem làm thế nào tôi có thể sử dụng với một tiện ích đã được thiết kế để chạy từ bên trong QGIS.

Phần "Kiểm tra" trong tài liệu PyQGIS đáng chú ý là không có.

Những gì tôi có cho đến nay là:

  • Giữ việc xử lý dữ liệu thực tế trong các mô-đun hoặc chức năng riêng biệt và viết các bài kiểm tra đơn vị cho các mô-đun đó;
  • Thực hiện kiểm tra cơ bản về UI bằng cách sử dụng QTest;
  • Xin cầu nguyện rằng tất cả sẽ kết hợp với nhau khi sử dụng plugin từ bên trong QGIS.

Có cách nào tốt hơn?

Câu trả lời:


11

Các khả năng kiểm tra các plugin QGIS (đặc biệt là câu hỏi về kiểm thử tích hợp, trong môi trường QGIS, như các điểm nổi bật của OP) đã cải thiện rất nhiều gần đây. Do đó, tôi hy vọng bản cập nhật này sẽ giúp ích cho độc giả đương đại, cũng như OP.

Boundless đã xuất bản một bài báo phải đọc vào tháng 7 năm 2016 cho bất kỳ ai nghiêm túc về việc tự động kiểm tra các plugin của QGIS có quyền; Môi trường thử nghiệm tích hợp liên tục của QGIS cho các plugin Python . Nó mô tả cách tiếp cận và các công cụ họ sử dụng - tất cả đều là nguồn mở. Các khía cạnh chính là: -

  • Trình kiểm tra plugin QGIS đặc biệt của họ có thể tự động hóa các kiểm tra bên trong môi trường QGIS
  • Việc sử dụng Docker QGIS hình ảnh, cho phép thử nghiệm chống lại các phiên bản QGIS / cấu hình khác nhau trong một môi trường chứa-base
  • Một hình ảnh QGIS docker đặc biệt , được sử dụng để kiểm tra chính QGIS, nhưng mà - bằng cách gọi qgis_testrunner.shcó thể được sử dụng để chạy thử nghiệm đơn vị trên một plugin
  • Việc sử dụng Travis CI để tích hợp liên tục - tức là bộ kiểm tra đầy đủ được chạy với mọi cam kết mã mới

Nếu bạn đã quen thuộc với Travis CI / docker thì việc cài đặt tương đối dễ dàng. Họ mô tả 4 bước sau đây và cung cấp 2 ví dụ về các plugin của riêng họ được thiết lập theo cách này.

  1. Kéo hình ảnh Docker với môi trường thử nghiệm QGIS và chạy nó
  2. Chạy qgis_setup.sh NameOfYourPlugin để cài đặt plugin và chuẩn bị QGIS cho người chạy thử nghiệm
  3. Tùy chọn thực hiện tất cả các hoạt động cần thiết để xây dựng plugin của bạn
  4. Chạy trình chạy thử bên trong Docker gọi qgis_testrunner.sh

Bạn đã yêu cầu thực hành tốt nhất và cho đến hôm nay tôi chắc chắn sẽ xem xét nó. Các tài liệu của QGIS vẫn chưa có phần dành riêng cho thử nghiệm plugin (tôi hy vọng điều này sẽ sớm thay đổi) nhưng phương pháp "Xin cầu nguyện rằng tất cả sẽ giữ lại với nhau" chắc chắn không còn là lựa chọn duy nhất.


4
Vô biên không còn nữa. Có ai đã lưu nội dung đó chưa?
Pedro Camargo

8

Có vẻ như điều này có thể được sử dụng unittestđể kiểm tra các plugin Python được tải vào một ứng dụng Python độc lập .

qgis.core.iface không có sẵn từ các ứng dụng độc lập, vì vậy tôi đã viết một ví dụ giả trả về một hàm sẽ chấp nhận bất kỳ đối số nào được cung cấp cho nó và không làm gì khác. Điều này có nghĩa là các cuộc gọi như self.iface.addToolBarIcon(self.action)không ném lỗi.

Ví dụ dưới đây tải một plugin myplugin, trong đó có một số menu thả xuống với tên lớp được lấy từ sổ đăng ký lớp bản đồ. Các thử nghiệm kiểm tra xem các menu đã được xác định chính xác chưa và có thể tương tác với nhau không. Tôi không chắc đây có phải là cách tốt nhất để tải plugin hay không, nhưng có vẻ như nó hoạt động.

tiện ích 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
Kể từ khi tôi viết một bài báo dựa trên câu trả lời này tại đây: snorf.net/blog/2014/01/04/ Kẻ
Snorfalorpagus

3

Tôi cũng đã đặt một DummyInterface cùng nhau, cho phép bạn kiểm tra các plugin bổ trợ của QGIS. Sau khi đọc blog của Snorfalorpagus, hãy xem câu trả lời của tôi ở đây .

Để tìm một ví dụ thực tế, về cách tôi kiểm tra (ed) các plugin QGIS, hãy truy cập dự án github này tại https://github.com/UdK-VPT/Open_eQuarter/tree/master/mole và xem xét các bài kiểm tra - gói.


-1

Điều này có thể giúp: Kiểm tra GUI PyQt với QTest và unittest http://www.voom.net/pyqt-qtest-example


1
Đó là "trang này" được liên kết đến trong câu hỏi (phải thừa nhận là không quá rõ ràng). Vấn đề của tôi là, làm cách nào để kiểm tra một giao diện được thiết kế để chạy với những thứ như hộp tổ hợp có các lớp trong QGIS.
Snorfalorpagus
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.