My use of mocks isn't as sophisticated as Dave's, perhaps, but I stumbled onto a simple testing pattern that might be useful to other Python geospatial/GIS developers who are wrapping C libs using ctypes.
Consider Shapely: it wraps the GEOS library, the quality and accuracy of which we take as a given (though not blindly, because I do contribute fixes and enhancements to GEOS). The predicates and topological functions of GEOS are called from within Python descriptors, classes that perform argument validation and handle GEOS errors. For Shapely, I'm testing these descriptors, the GEOS wrappers, not GEOS itself. What pair of geometries would I have to pass to GEOSDisjoint (for example) in order to get the return value of 2 that signifies an error? Even if known, they might be subject to issues of numerical precision, or be sensitive to changes in GEOS. I'd rather not fuss with this. Instead, I want some function to stand in for GEOSDisjoint and friends, one that takes 2 arguments and has very predictable return values in the range (0, 1, 2). A function like libc's strcmp():
>>> import ctypes >>> libc = ctypes.CDLL('libc.dylib') # this is OS X >>> libc.strcmp('\0', '\0') 0 >>> libc.strcmp('\1', '\0') 1 >>> libc.strcmp('\2', '\0') 2
Meaningless, but handy, isomorphism between strcmp() and GEOS binary operations in hand, a generic wrapper for GEOS can be fully tested like this:
import ctypes import unittest from shapely import predicates BN = libc.strcmp class CompMockGeom(object): # Values chosen with libc.strcmp in mind vals = {'0': '\0', '1': '\1', '2': '\2'} def __init__(self, cat): self._geom = ctypes.c_char_p(self.vals[cat]) comp = predicates.BinaryPredicate(BN) class BinaryPredicateAttributeTestCase(unittest.TestCase): def test_bin_false(self): g1 = CompMockGeom('0') g2 = CompMockGeom('0') self.assertEquals(g1.comp(g2), False) def test_bin_true(self): g1 = CompMockGeom('1') g2 = CompMockGeom('0') self.assertEquals(g1.comp(g2), True) def test_bin_error(self): g1 = CompMockGeom('2') g2 = CompMockGeom('0') self.assertRaises(predicates.PredicateError, g1.comp, g2)
Comments are closed after 13 days.
1Re: Mocking GEOS
ajfowler, 2009-01-20T22:23:33Z