|
| 1 | +******************* |
| 2 | +Labeling Unit Tests |
| 3 | +******************* |
| 4 | + |
| 5 | +Design and Organization |
| 6 | +======================= |
| 7 | + |
| 8 | +The labeling unit tests are solely written in Python and are organized so that |
| 9 | +individual tests are separated from, but inherited by, the output frameworks. |
| 10 | +This allows maintaining output-agnostic units, focusing only on the code to be |
| 11 | +tested, which the frameworks will use to generate as many tests as necessary, |
| 12 | +cross-referencing outputs as needed. |
| 13 | + |
| 14 | +The goal of this design, beyond API and regression testing, is to ensure labels |
| 15 | +crafted by users have as close to a WYSIWYG rendering as possible across all |
| 16 | +potential outputs and platforms. Exact parity is not achievable; so the test |
| 17 | +suite is designed to be flexible enough to maintain a 'best case' scenario. |
| 18 | + |
| 19 | +Modules |
| 20 | +------- |
| 21 | + |
| 22 | +test_qgspallabeling_base |
| 23 | + Provides the ``TestQgsPalLabeling`` base class, which is inherited by all |
| 24 | + other test classes. ``TestPALConfig`` tests the configuration of the PAL |
| 25 | + placement engine, and project and map layer settings. |
| 26 | + |
| 27 | +test_qgspallabeling_tests |
| 28 | + Individual unit tests are to be placed here, unless a test *needs* to be |
| 29 | + placed in a specific test subclass. Tests are separated into logical |
| 30 | + groupings for labeling: `single point`, `single line`, `single polygon`, |
| 31 | + `multi-feature`, `placement`. Most label styling tests that are not |
| 32 | + feature-dependant are associated with `single point`. |
| 33 | + |
| 34 | + Almost all tests produce many images for comparison to controls. To keep |
| 35 | + the proliferation of control images to a minimum, several options can be |
| 36 | + grouped, e.g. SVG background, with buffer, offset and rotation. If such a |
| 37 | + grouping is found to be problematic, it can be separated later. |
| 38 | + |
| 39 | + Some values for specific, inherited class/function tests can be passed; for |
| 40 | + example, pixel mismatch and color tolerance values for image comparison:: |
| 41 | + |
| 42 | + def test_default_label(self): |
| 43 | + # Default label placement, with text size in points |
| 44 | + self._Mismatches['TestComposerPdfVsComposerPoint'] = 760 |
| 45 | + self._ColorTols['TestComposerPdfVsComposerPoint'] = 18 |
| 46 | + self.checkTest() |
| 47 | + |
| 48 | + Values would replace the default values for the module or class, if any, for |
| 49 | + the ``TestComposerPdfVsComposerPoint.test_default_label`` generated test. |
| 50 | + |
| 51 | +test_qgspallabeling_canvas |
| 52 | + ``TestCanvas*`` framework for map canvas output to `image`. |
| 53 | + |
| 54 | +test_qgspallabeling_composer |
| 55 | + ``TestComposer*`` framework for composer map item output to `image`, `SVG` |
| 56 | + and `PDF`. Compares *composition->image* against *canvas->image*, and other |
| 57 | + composer outputs against *composition->image*. |
| 58 | + |
| 59 | + **Requires:** PDF->image conversion utility, e.g. Poppler, with Cairo |
| 60 | + support: `pdftocairo`. |
| 61 | + |
| 62 | +test_qgspallabeling_server |
| 63 | + ``TestServer*`` framework for ``qgis_mapserv.fcgi`` output to `image`. |
| 64 | + Compares *qgis_mapserv->image* against *canvas->image*. Utilizes the |
| 65 | + ``qgis_local_server`` module. |
| 66 | + |
| 67 | +qgis_local_server |
| 68 | + A local-only, on-demand server process controller to aid unit tests. It is |
| 69 | + launched with a custom configuration and independently manages the HTTP and |
| 70 | + FCGI server processes. |
| 71 | + |
| 72 | + **Requires:** HTTP and FCGI-spawning utilities, e.g. `lighttpd` |
| 73 | + and `spawn-fcgi`. |
| 74 | + |
| 75 | +test_qgis_local_server |
| 76 | + Unit tests for ``qgis_local_server``. |
| 77 | + |
| 78 | +Running the Suite |
| 79 | +================= |
| 80 | + |
| 81 | +Since the overall suite and frameworks will generate many units, making manual |
| 82 | +management of label tests quite tedious, there are extra tools provided to aid |
| 83 | +unit test authors. The tools are generally triggered via setting environment |
| 84 | +variables, though some work sessions may require un/commenting configuration |
| 85 | +lines in multiple files. |
| 86 | + |
| 87 | +Test modules can be run on the command line using CTest's regex support. The |
| 88 | +CTest name is listed in the module's docstring, e.g. PyQgsPalLabelingCanvas:: |
| 89 | + |
| 90 | + # run just test_qgspallabeling_canvas in verbose mode |
| 91 | + $ ctest -R PyQgsPalLabelingCanvas -V |
| 92 | + |
| 93 | + # run all PAL test modules; all CTest names start with PyQgsPalLabeling |
| 94 | + $ ctest -R PyQgsPalLabeling |
| 95 | + |
| 96 | +Environment variables |
| 97 | +--------------------- |
| 98 | + |
| 99 | +These are all flags that only need to be set or unset, e.g. (using bash):: |
| 100 | + |
| 101 | + # set |
| 102 | + $ export PAL_VERBOSE=1 |
| 103 | + |
| 104 | + # unset (note: export PAL_VERBOSE=0 will NOT work) |
| 105 | + $ unset PAL_VERBOSE |
| 106 | + |
| 107 | +PAL_VERBOSE |
| 108 | + The Python unit test modules, as run via CTest, will not output individual |
| 109 | + class/function test results, only whether the module as a whole succeeded or |
| 110 | + failed. Setting this variable will print individually run class/function |
| 111 | + test results, up to the point where any exception is raised. |
| 112 | + |
| 113 | + In addition to setting the variable, CTest needs run in verbose mode. |
| 114 | + |
| 115 | + **Sample session**:: |
| 116 | + |
| 117 | + $ cd <qgis-build-dir> |
| 118 | + $ export PAL_VERBOSE=1 |
| 119 | + $ ctest -R PyQgsPalLabelingCanvas -V |
| 120 | + ... |
| 121 | + 85: test_default_label (__main__.TestCanvasPoint) ... ok |
| 122 | + 85: test_text_size_map_unit (__main__.TestCanvasPoint) ... ok |
| 123 | + 85: test_text_color (__main__.TestCanvasPoint) ... ok |
| 124 | + 85: test_background_rect (__main__.TestCanvasPoint) ... FAILED |
| 125 | + ... |
| 126 | + 85: ---------------------------------------------------------- |
| 127 | + 85: Ran X tests in X.Xs |
| 128 | + |
| 129 | + 1/1 Test #85: PyQgsPalLabelingCanvas ........... FAILED X.XX sec |
| 130 | + |
| 131 | + The following tests failed: |
| 132 | + PyQgsPalLabelingCanvas |
| 133 | + |
| 134 | +PAL_REPORT |
| 135 | + Setting this variable will open an HTML report of any failed image |
| 136 | + comparisons as a grouped report in your default web browser. This is the |
| 137 | + HTML output from ``QgsRenderChecker`` wrapped in a local report. It is |
| 138 | + **highly recommended** setting this when creating new unit tests to visually |
| 139 | + debug any issues *before* committing. Otherwise, all other nightly test |
| 140 | + machines may build and run tests, flooding the online test collation server |
| 141 | + with possibly avoidable CDash failed test reports. |
| 142 | + |
| 143 | +PAL_SUITE |
| 144 | + Since you cannot define specific class/function tests when running the |
| 145 | + modules via the CTest command, setting this variable will allow defining |
| 146 | + specific tests to run, e.g. any number of class/function tests, suite |
| 147 | + groupings, or all tests. |
| 148 | + |
| 149 | + All base units and suite groupings are listed in ``suiteTests()`` of |
| 150 | + ``test_qgspallabeling_tests``, with all unit tests commented out by default. |
| 151 | + (Please keep them commented out when committing.) |
| 152 | + |
| 153 | + Some modules, like ``test_qgspallabeling_composer``, generate tests for |
| 154 | + multiple outputs or cross-reference comparisons. Those files have the test |
| 155 | + suite separately extended, per line, to help define test selection. |
| 156 | + |
| 157 | + **Sample session**:: |
| 158 | + |
| 159 | + $ cd <qgis-build-dir> |
| 160 | + $ export PAL_VERBOSE=1 |
| 161 | + $ export PAL_SUITE=1 |
| 162 | + |
| 163 | + $ nano <qgis-src-dir>/tests/src/python/test_qgspallabeling_tests.py |
| 164 | + # uncomment units you want to test |
| 165 | + # e.g. only 'test_default_label', is now active |
| 166 | + |
| 167 | + $ nano <qgis-src-dir>/tests/src/python/test_qgspallabeling_composer.py |
| 168 | + # comment-out undesired extended suite lines, i.e. suite.extend(*) |
| 169 | + # e.g. only 'suite.extend(sp_pvs)' is now active |
| 170 | + # note: this step is unnecessary for modules without extended suites |
| 171 | + # or when you wish to test all available suites |
| 172 | + |
| 173 | + $ ctest -R PyQgsPalLabelingComposer -V |
| 174 | + |
| 175 | + Above will only run ``TestComposerPdfVsComposerPoint.test_default_label`` in |
| 176 | + verbose mode and no other tests. This is especially useful for debugging a |
| 177 | + single test or group, and for (re)building control images. |
| 178 | + See PAL_CONTROL_IMAGE. |
| 179 | + |
| 180 | +PAL_NO_MISMATCH and PAL_NO_COLORTOL |
| 181 | + Some test classes or units may have a default allowable pixel mismatch |
| 182 | + and/or color tolerance value for image comparison. Reset the allowable |
| 183 | + mismatch or tolerance to *zero* by setting one (or both) of these variables, |
| 184 | + effectively bypassing all defined defaults. Either of these, coupled with |
| 185 | + PAL_REPORT, helps determine actual differences and whether defaults are |
| 186 | + allowing (masking) a false positive result. |
| 187 | + |
| 188 | +PAL_CONTROL_IMAGE |
| 189 | + Setting this variable will (re)build control images for selected tests. |
| 190 | + When being rebuilt, the associated unit test should *always* pass. Any class |
| 191 | + that contains a 'Vs' string, i.e. all cross-comparison checks, will not |
| 192 | + have images built, since the rendered test image is always compared against |
| 193 | + an existing control image of a different test class. |
| 194 | + |
| 195 | + **CAUTION:** Do not leave this set. Unset it immediately after building any |
| 196 | + needed control images. You can reset any accidentally overwritten control |
| 197 | + images using ``git``, however. |
| 198 | + |
| 199 | +PAL_SERVER_TEMP |
| 200 | + Used only in ``test_qgspallabeling_server``. When set, opens the temporary |
| 201 | + HTML server directory, instead of deleting it, upon test class completion. |
| 202 | + This is useful when debugging tests, since the directory contains server |
| 203 | + process logs and the generated test project file. |
0 commit comments