{"id":7807,"date":"2018-12-10T07:30:57","date_gmt":"2018-12-10T10:30:57","guid":{"rendered":"http:\/\/www.fernandoquadro.com.br\/html\/?p=7807"},"modified":"2018-11-29T13:42:11","modified_gmt":"2018-11-29T16:42:11","slug":"desenvolvimento-de-plugins-do-qgis-testando-seu-codigo-parte-6","status":"publish","type":"post","link":"https:\/\/www.fernandoquadro.com.br\/html\/2018\/12\/10\/desenvolvimento-de-plugins-do-qgis-testando-seu-codigo-parte-6\/","title":{"rendered":"Desenvolvimento de plugins do QGIS: Testando seu c\u00f3digo"},"content":{"rendered":"<p>Neste post (o \u00faltimo da s\u00e9rie) veremos o teste do plugin que criamos para o QGIS.<\/p>\n<p><strong>1. MOCKING<\/strong><\/p>\n<p>Para testar um plugin do QGIS voc\u00ea precisa simular o ambiente que ele deve rodar. E esse ambiente \u00e9 obviamente o pr\u00f3prio QGIS, mas n\u00e3o \u00e9 poss\u00edvel iniciar o QGIS toda vez que voc\u00ea executa um teste. Felizmente, h\u00e1 o <a href=\"https:\/\/github.com\/zimmicz\/qgis-attribute-transfer-plugin\/blob\/master\/tests\/utilities.py\" rel=\"noopener\" target=\"_blank\">QGIS Mocking<\/a> para lhe auxiliar.<\/p>\n<p><strong>2. VOC\u00ca PRECISA DE DADOS<\/strong><\/p>\n<p>Cada teste \u00e9 executado repetidas vezes, o que significa que ele precisa redefinir os dados que est\u00e3o sendo usados \u200b\u200bpara seu estado padr\u00e3o. Isso pode ser um &#8220;PIDA&#8221; se o teste alterar os dados de maneira imprevis\u00edvel.<\/p>\n<p>Usando as camadas do QGIS, voc\u00ea pode <a href=\"https:\/\/github.com\/zimmicz\/qgis-attribute-transfer-plugin\/blob\/master\/tests\/create_dummy_data.py\" rel=\"noopener\" target=\"_blank\">preparar novos dados<\/a> para cada um dos seus testes, colocando de forma eficaz todo o processo de manipula\u00e7\u00e3o de dados.<\/p>\n<p><strong>3. ESCREVENDO TESTES<\/strong><\/p>\n<p>Cada um dos testes do plugin AttributeTransfer herda da classe <strong>unittest.TestCase<\/strong>, que vem com v\u00e1rios m\u00e9todos que voc\u00ea pode estar familiarizado com outros idiomas: <strong>setUp()<\/strong> \u00e9 executado antes para cada m\u00e9todo de teste, enquanto <strong>tearDown()<\/strong> \u00e9 executado ap\u00f3s cada um deles. Os testes s\u00e3o definidos como m\u00e9todos cujos nomes come\u00e7am com a palavra test.<\/p>\n<p>Cada teste deve chamar algum m\u00e9todo <strong>assertWhatever<\/strong> que verifica se o teste foi aprovado ou n\u00e3o. Aqui est\u00e1 um exemplo de tal teste cobrindo camadas n\u00e3o pontuais.<\/p>\n<pre>\r\n#!\/usr\/bin\/env python\r\n# -*- coding: utf-8 -*-\r\n# @Date    : 2017-11-18 18:40:50\r\n# @Author  : Michal Zimmermann &lt;zimmicz@gmail.com&gt;\r\n\r\nimport os\r\nimport sip\r\nimport sys\r\nimport unittest\r\nfrom qgis.core import QgsMapLayerRegistry, QgsVectorLayer, QgsFeature, QgsGeometry, QgsPoint\r\nfrom utilities import get_qgis_app\r\n\r\nsys.path.append(os.path.dirname(os.path.abspath(__file__)) + \"\/..\")\r\nfrom attribute_transfer import AttributeTransfer\r\nfrom create_dummy_data import create_dummy_data_polygon_or_line\r\n\r\nsip.setapi('QtCore', 2)\r\nsip.setapi('QString', 2)\r\nsip.setapi('QDate', 2)\r\nsip.setapi('QDateTime', 2)\r\nsip.setapi('QTextStream', 2)\r\nsip.setapi('QTime', 2)\r\nsip.setapi('QUrl', 2)\r\nsip.setapi('QVariant', 2)\r\n\r\nQGIS_APP = get_qgis_app()\r\nIFACE = QGIS_APP[2]\r\n\r\n\r\nclass AttributeTransferTestPolygonOrLine(unittest.TestCase):\r\n\r\n    def setUp(self):\r\n        self.source_layer = QgsVectorLayer(\r\n            \"Polygon?crs=epsg:4326&amp;field=id:integer&amp;field=textAttr:string&amp;field=intAttr:integer&amp;field=decAttr:double&amp;field=dateAttr:date&amp;index=yes\", \"source layer\", \"memory\")\r\n        self.target_layer = QgsVectorLayer(\r\n            \"Linestring?crs=epsg:4326&amp;field=id:integer&amp;index=yes\", \"target layer\", \"memory\")\r\n        self.widget = AttributeTransfer(IFACE)\r\n\r\n        registry = QgsMapLayerRegistry.instance()\r\n        registry.removeAllMapLayers()\r\n        registry.addMapLayers([self.source_layer, self.target_layer])\r\n        create_dummy_data_polygon_or_line(self.source_layer, self.target_layer)\r\n        self.widget.initGui()\r\n        self.widget.vectors = [self.source_layer, self.target_layer]\r\n        self.widget.editable_vectors = [self.source_layer, self.target_layer]\r\n        self.widget.dlg.sourceLayer.addItems([\"source layer\", \"target layer\"])\r\n\r\n    def test_text_attr(self):\r\n        ATTRIBUTE_NAME = \"textAttr\"\r\n        ATTRIBUTE_INDEX = 1\r\n\r\n        self._test_attr(ATTRIBUTE_NAME, ATTRIBUTE_INDEX)\r\n\r\n    def test_int_attr(self):\r\n        ATTRIBUTE_NAME = \"intAttr\"\r\n        ATTRIBUTE_INDEX = 2\r\n\r\n        self._test_attr(ATTRIBUTE_NAME, ATTRIBUTE_INDEX)\r\n\r\n    def test_dec_attr(self):\r\n        ATTRIBUTE_NAME = \"decAttr\"\r\n        ATTRIBUTE_INDEX = 3\r\n\r\n        self._test_attr(ATTRIBUTE_NAME, ATTRIBUTE_INDEX)\r\n\r\n    def test_date_attr(self):\r\n        ATTRIBUTE_NAME = \"dateAttr\"\r\n        ATTRIBUTE_INDEX = 4\r\n\r\n        self._test_attr(ATTRIBUTE_NAME, ATTRIBUTE_INDEX)\r\n\r\n    def test_existing_attr(self):\r\n        ATTRIBUTE_NAME = \"id\"\r\n        ATTRIBUTE_INDEX = 0\r\n\r\n        self.widget.dlg.sourceAttribute.setCurrentIndex(ATTRIBUTE_INDEX)\r\n        self.widget.dlg.targetAttribute.setText(ATTRIBUTE_NAME)\r\n\r\n        self.assertEqual(\r\n            self.widget.dlg.sourceAttribute.currentText(), ATTRIBUTE_NAME)\r\n        self.assertFalse(self.widget.transfer())\r\n\r\n    def _test_attr(self, attr_name, attr_index):\r\n        self.widget.dlg.sourceAttribute.setCurrentIndex(attr_index)\r\n        self.widget.dlg.targetAttribute.setText(attr_name)\r\n\r\n        self.assertEqual(\r\n            self.widget.dlg.sourceAttribute.currentText(), attr_name)\r\n\r\n        self.widget.transfer()\r\n\r\n        target_fields = [f.name()\r\n                         for f in self.target_layer.dataProvider().fields()]\r\n        self.assertIn(attr_name, target_fields)\r\n\r\n        source_features = [f for f in self.source_layer.getFeatures()]\r\n        target_features = [f for f in self.target_layer.getFeatures()]\r\n\r\n        for idx, f in enumerate(source_features):\r\n            self.assertEqual(f.attribute(attr_name), target_features[\r\n                             idx].attribute(attr_name))\r\n\r\n\r\nif __name__ == \"__main__\":\r\n    unittest.main()\r\n\r\n<\/pre>\n<p>Com esse teste encerro a s\u00e9rie de posts sobre como desenvolver um plugin para o QGIS. Espero que tenha ajudado a voc\u00ea que est\u00e1 querendo criar ou est\u00e1 criando o seu plugin para o QGIS.<\/p>\n<p><em>Esta s\u00e9rie de posts \u00e9 tradu\u00e7\u00e3o e uma adapta\u00e7\u00e3o livre do post escrito originalmente por Michal Zimmermann do blog &#8220;<a href=\"https:\/\/www.zimmi.cz\/posts\/\" rel=\"noopener\" target=\"_blank\">Pieces of knowledge from the world of GIS<\/a>&#8220;<\/em>.<\/p>\n<p>Fonte: <a href=\"https:\/\/www.zimmi.cz\/posts\/2017\/qgis-plugin-development-getting-started\/\" rel=\"noopener\" target=\"_blank\">Pieces of knowledge from the world of GIS<\/a> <\/p>\n","protected":false},"excerpt":{"rendered":"<p>Neste post (o \u00faltimo da s\u00e9rie) veremos o teste do plugin que criamos para o QGIS. 1. MOCKING Para testar um plugin do QGIS voc\u00ea precisa simular o ambiente que ele deve rodar. E esse ambiente \u00e9 obviamente o pr\u00f3prio&#8230; <a class=\"more-link\" href=\"https:\/\/www.fernandoquadro.com.br\/html\/2018\/12\/10\/desenvolvimento-de-plugins-do-qgis-testando-seu-codigo-parte-6\/\">Continue Reading &rarr;<\/a><\/p>\n","protected":false},"author":275,"featured_media":7810,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[24],"tags":[79,260],"class_list":["post-7807","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-gis","tag-python","tag-qgis"],"_links":{"self":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts\/7807","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/users\/275"}],"replies":[{"embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/comments?post=7807"}],"version-history":[{"count":10,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts\/7807\/revisions"}],"predecessor-version":[{"id":7826,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/posts\/7807\/revisions\/7826"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/media\/7810"}],"wp:attachment":[{"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/media?parent=7807"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/categories?post=7807"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.fernandoquadro.com.br\/html\/wp-json\/wp\/v2\/tags?post=7807"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}