|
1 | | -======================================================================== |
2 | | - matplotlib test structure |
3 | | -======================================================================== |
4 | | - |
5 | | -===== How To Use |
6 | | - |
7 | | -= Running |
8 | | - |
9 | | -Run the 'run-mpl-test.py' script to execute the test harness. This must |
10 | | -be run with the version of python that you wish to test matplotlib with. |
11 | | -This means that it must have nose installed (and PIL if image comparison |
12 | | -is to be done). By default this will pick up whatever python is on your |
13 | | -path, so make sure it is the correct one. |
14 | | - |
15 | | -- Command-Line Options |
16 | | -In addition to the standard nose command-line options, there are several |
17 | | -specific to the matplotlib test harness. They are as follows: |
18 | | - |
19 | | - -t TAG, --with-tag=TAG |
20 | | - Will only run test cases that have the specified tag. |
21 | | - Each test case should have a 'tag' attribute (if a |
22 | | - case does not have one, then it is assumed to be an |
23 | | - empty list). The 'tag' attribute is a list of |
24 | | - strings, where each value is a representative propery |
25 | | - of the test case. Example tags are 'qt' or 'units'. |
26 | | - This can be specified multiple times. |
27 | | - --without-tag=TAG This will run those test cases that do not have the |
28 | | - specified tags. |
29 | | - --clean This will remove all output files and saved results. |
30 | | - If this is specified, no other processing will be |
31 | | - performed. |
32 | | - --all This will runn all test programs regardless of working |
33 | | - directory. |
34 | | - --keep Keep any generated output files in a directory called |
35 | | - 'saved-results'. This directory will be created if it |
36 | | - doesn't already exist. This directory is in the same |
37 | | - location as the test case whose results are being |
38 | | - saved. |
39 | | - --keep-failed This acts just like '--keep' except will only keeps |
40 | | - the results from tests that error or fail. |
41 | | - --make-test=testName |
42 | | - Creates a template test case file in the current |
43 | | - directory with the name TestFoo. Where 'Foo' is the |
44 | | - provided test name. |
45 | | - |
46 | | - |
47 | | -- Running Specific Tests |
48 | | -In order to can specify the exact test case you want to run use the |
49 | | -standard nose mechanism. For example, if you have the following setup: |
50 | | - |
51 | | -TestFoo.py |
52 | | - def test_func(): |
53 | | - ... |
54 | | - |
55 | | - class TestFoo: |
56 | | - def test_bar( self ): |
57 | | - ... |
58 | | - def test_bug( self ): |
59 | | - ... |
60 | | - |
61 | | -Then to test everything in TestFoo.py do the following: |
62 | | -$> run-mpl-test.py TestFoo.py |
63 | | - |
64 | | -To run all tests in the test class TestFoo do this: |
65 | | -$> run-mpl-test.py TestFoo.py:TestFoo |
66 | | - |
67 | | -To run the specific 'test_bar' methodd do the following: |
68 | | -$> run-mpl-test.py TestFoo.py:TestFoo.test_bar |
69 | | - |
70 | | - |
71 | | -= Detecting Test Cases |
72 | | - |
73 | | -When running the matplotlib test script it will search for all tests |
74 | | -in the current working directory and below (unless '--all' is specified). |
75 | | -This is provided that the current working directory is a sub-directory |
76 | | -of the matplotlib test directory. In the event that it is not, then the |
77 | | -matplotlib root test directory will be used and all appropriate test cases |
78 | | -will be run. |
79 | | - |
80 | | -This will not search outside of the test structure and will not look in |
81 | | -the mplTest module. This will only search for test cases in the root |
82 | | -test directory and any of its sub-directories. |
83 | | - |
84 | | -= Saving Results |
85 | | - |
86 | | -When using the keep flag any generated files in the 'output' directory |
87 | | -are copied to the 'saved-results/<classname>' directory, where <classname> |
88 | | -is the name of the unit-test class. This means that for each test case |
89 | | -within a given test class, all output files should have unique names. |
90 | | - |
91 | | -The 'saved-results' directory will always contain the results from the |
92 | | -last test run. This is considered a volatile directory since running |
93 | | -the test cases without the '--keep' flag will remove any existing |
94 | | -'saved-results' directory. This is to ensure the integrity of the |
95 | | -saved results, they will always match the last test run. |
96 | | - |
97 | | -= Filtering Tests |
98 | | - |
99 | | -In the case of filtering via tags, a unit-test cane have multiple tags. |
100 | | -When running the test program if any tags are specified as 'skip' then |
101 | | -this will take precedence over any tags that might say 'process'. For |
102 | | -example, if a test case has both the 'gui' and 'qt' tag, but the command- |
103 | | -line is specified with the following flags: |
104 | | - '--with-tag=gui --without-tag=qt' |
105 | | -then the example test case will not be run because it matches the skip |
106 | | -tag. |
107 | | - |
108 | | - |
109 | | -===== Directory Structure |
110 | | - |
111 | | -There are several directories in the matplotlib test structure. The first |
112 | | -directory is the 'mplTest' directory. This is the matplotlib test module |
113 | | -and contains the various python scripts that the test harness needs to |
114 | | -run. The remaining directories are as follows and contain the various test |
115 | | -cases for matplotlib. |
116 | | - |
117 | | -mplTest |
118 | | - This directory does not contain any test cases, rather it is the location |
119 | | - of the matplotlib specific utilities for performing unit tests. |
120 | | - |
121 | | -test_artists |
122 | | - This directory contains tests that focus on the rendering aspects of |
123 | | - the various artists. Essentially the artist derived functionality. |
124 | | - |
125 | | -test_backends |
126 | | - This directory contains various tests that focus on making sure the |
127 | | - various backend targets work. |
128 | | - |
129 | | -test_basemap |
130 | | - This directory contains test cases that excercise the basemap add-on |
131 | | - module. |
132 | | - |
133 | | -test_cxx |
134 | | - This directoy contains tests that focus on testing the interface of |
135 | | - the compiled code contained in matplotlib. |
136 | | - |
137 | | -test_mathtext |
138 | | - This directory contains tests that focus on excercising the mathtext |
139 | | - sub-system. |
140 | | - |
141 | | -test_numerix |
142 | | - This directory contains tests that focus on validating the numerix |
143 | | - component. |
144 | | - |
145 | | -test_plots |
146 | | - This directory contains tests that validate the various plot funtions. |
147 | | - |
148 | | -test_pylab |
149 | | - This directory has pylab specific test cases. |
150 | | - |
151 | | -test_transforms |
152 | | - This directory has test cases that focus on testing the various |
153 | | - transformation and projection functions. |
154 | | - |
155 | | -test_matplotlib |
156 | | - This directory has all other test cases. This contins test that focus |
157 | | - on making sure that Axis, Axes, Figure, etc are all acting properly. This |
158 | | - has test cases that are general to the overall funtionality of matplotlib. |
159 | | - |
160 | | - |
161 | | -===== Writing Test Cases |
162 | | - |
163 | | -= The Test Case |
164 | | - |
165 | | -As per the nose implementation, a test case is ultimately any function that |
166 | | -has the phrase 'test' in its name. The matplotlib cases however are grouped |
167 | | -into directories, by what is being tested, and from there are grouped into |
168 | | -classes (one class per file), by similarity. |
169 | | - |
170 | | -It is desireable that all matplotlib tests follow the same structure to |
171 | | -not only facilitate the writing of test cases, but to make things easier |
172 | | -for maintaining them and keeping things uniform. |
173 | | - |
174 | | -There is a class 'MplTestCase' provided to be the base class for all matplotlib |
175 | | -test classes. This class provides some extra functionality in the form of |
176 | | -verification functions and test data management. |
177 | | - |
178 | | -= Comparison Functions |
179 | | - |
180 | | -There are several methods provided for testing whether or not a particular |
181 | | -test case should fail or succeed. The following methods are provided by |
182 | | -the base matplotlib test class: |
183 | | - |
184 | | -- MplTestCase.checkEq( expected, actual, msg = "" ) |
185 | | - Fail if the values are not equal, with the given message. |
186 | | - |
187 | | -- MplTestCase.checkNeq( expected, actual, msg = "" ) |
188 | | - Fail if the values are equal, with the given message. |
189 | | - |
190 | | -- MplTestCase.checkClose( expected, actual, relTol=None, absTol=None, msg="" ) |
191 | | - Fail if the floating point values are not close enough, with the given message. |
192 | | - You can specify a relative tolerance, absolute tolerance, or both. |
193 | | - |
194 | | -- MplTestCase.checkImage( filename, tol = 1.0e-3, msg = "" ) |
195 | | - Check to see if the image is similair to the one stored in the baseline |
196 | | - directory. filename can be a fully qualified name (via the 'outFile' method), |
197 | | - or it can be the name of the file (to be passed into the 'outFile' method). |
198 | | - The default tolerance is typically fine, but might need to be adjusted in some |
199 | | - cases (see the 'compareImages' function for more details). Fails with |
200 | | - the specified message. |
201 | | - |
202 | | -Note that several of the tests will perform image comparison for validation |
203 | | -of a specific plot. Though not 100% accurate it at least flags potential |
204 | | -failures and signals a human to come and take a closer look. If an image has |
205 | | -changed and after a human deems the change is acceptable, then updating the |
206 | | -baseline image with the appropriate image from the 'saved-results' directory |
207 | | -(when using the '--keep' or '--keep-failed' command-line arguments) will make |
208 | | -the test pass properly. |
209 | | - |
210 | | -Image comparison depends on the python imaging library (PIL) being installed. |
211 | | -If PIL is not installed, then any test cases that rely on it will not |
212 | | -pass. To not run these test cases, then pass the '--without-tag=PIL' |
213 | | -option on the command-line. |
214 | | - |
215 | | -= Directories |
216 | | - |
217 | | -Input data files for a given test case should be place in a directory |
218 | | -called 'inputs' with the test case that uses it. A convienence function |
219 | | -is provided with each test class for accessing input files. |
220 | | - |
221 | | -For example if a test case has an input file of the name 'inputs.txt' |
222 | | -you can get the path to the file by calling 'self.inFile("inputs.txt")'. |
223 | | -This is to allow for a uniform convention that all test cases can follow. |
224 | | - |
225 | | -Output files are handled just like input files with the exception that |
226 | | -they are written to the 'output' directory and the path name can be |
227 | | -had by calling 'self.outFile'. It is more important to use this mechanism |
228 | | -for getting the pathname for an output file because it allows for the |
229 | | -management of cleaning up and saving generated output files (It also |
230 | | -significantly reduces the probability of typo errors when specifying |
231 | | -where to place the files). |
232 | | - |
233 | | -A Third and final directory used by the test cases is the 'baseline' |
234 | | -directory. This is where data files used for verifying test results |
235 | | -are stored. The path name can be had by using the 'self.baseFile' |
236 | | -method. |
237 | | - |
238 | | -Accessing these directories can be made simple (and reduce the chance of a |
239 | | -typo) via the following MplTestCase methods: |
240 | | - |
241 | | -- MplTestCase.inFile( filename ) |
242 | | - Returns the full pathname of filename in the input data directory. |
243 | | - |
244 | | -- MplTestCase.outFile( filename ) |
245 | | - Returns the full pathname of filename in the output data directory. |
246 | | - |
247 | | -- MplTestCase.baseFile( filename ) |
248 | | - Returns the full pathname of filename in the baseline data directory. |
249 | | - |
250 | | -= Units |
251 | | - |
252 | | -Located in the mplTest directory is a set of unit classes. These classes |
253 | | -are provided for testing the various unitized data interfaces that matplotlib |
254 | | -supports (ie unit conversion). These are used because they provide a very |
255 | | -strict enforcement of unitized data which will test the entire spectrum of how |
256 | | -unitized data might be used (it is not always meaningful to convert to |
257 | | -a float without specific units given). This allows us to test for cases that |
258 | | -might accidentally be performing operations that really do not make sense |
259 | | -physically for unitized data. |
260 | | - |
261 | | -The provided classes are as follows: |
262 | | -- UnitDbl |
263 | | - UnitDbl is essentially a unitized floating point number. It has a |
264 | | - minimal set of supported units (enough for testing purposes). All |
265 | | - of the mathematical operation are provided to fully test any behaviour |
266 | | - that might occur with unitized data. Remeber that unitized data has |
267 | | - rules as to how it can be applied to one another (a value of distance |
268 | | - cannot be added to a value of time). Thus we need to guard against any |
269 | | - accidental "default" conversion that will strip away the meaning of the |
270 | | - data and render it neutered. |
271 | | - |
272 | | -- Epoch |
273 | | - Epoch is different than a UnitDbl of time. Time is something that can be |
274 | | - measured where an Epoch is a specific moment in time. Epochs are typically |
275 | | - referenced as an offset from some predetermined epoch. Conceptally an Epoch |
276 | | - is like saying 'January 1, 2000 at 12:00 UTC'. It is a specific |
277 | | - time, but more importantly it is a time with a frame. In the example |
278 | | - the frame is 'UTC'. This class is provided to test the functionality of |
279 | | - matplotlib's various routines and mechanisms for dealing with datetimes. |
280 | | - |
281 | | -- Duration |
282 | | - A difference of two epochs is a Duration. The distinction between a |
283 | | - Duration and a UnitDbl of time is made because an Epoch can have different |
284 | | - frames (or units). In the case of our test Epoch class the two allowed |
285 | | - frames are 'UTC' and 'ET' (Note that these are rough estimates provided for |
286 | | - testing purposes and should not be used in production code where accuracy |
287 | | - of time frames is desired). As such a Duration also has a frame of |
288 | | - reference and therefore needs to be called out as different that a simple |
289 | | - measurement of time since a delta-t in one frame may not be the same in another. |
290 | | - |
291 | | - |
292 | | - |
293 | | -Updating after diff |
294 | | -==================== |
295 | | - |
296 | | - python run-mpl-test.py --all --keep-failed |
297 | | - ./consolidate_diff_images.sh |
298 | | - # check your images, decide which are good |
299 | | - python movegood.py |
| 1 | +Please see doc/devel/coding_guide.rst for information about the |
| 2 | +testing infrastructure. |
0 commit comments