python ireland nov 2010 talk: unit testing
DESCRIPTION
Unit testing for those seeking instant gratification - Maciej Bliziński Abstract: Unit testing has long term benefits. However, depending on how you use it, it can have short term benefits too. This is an introductory talk, aimed at both beginner and experienced Python programmers who would like to get started testing their code.TRANSCRIPT
Unit testing
For those seeking instant gratification
Maciej Bliziński <[email protected]>Python Ireland 2010-11-10
Helps the designProvides live documentationHelps refactoring
But I'm hungry right now!
I love to see my code run
task: Index a list of dictionaries by one of the fields
def IndexBy(d_list, field_name): result = {} for d in d_list: result[d[field_name]] = d return result
def MakePackageNameBySoname(soname): """Find the package name based on the soname.
Returns a pair of pkgname, catalogname. """ def AddSeparator(d, sep): """Adds a separator based on the neighboring of two digits.""" dc = copy.copy(d) if dc["version"]: if (dc["basename"][-1].isdigit() and dc["version"][0].isdigit()): dc["sep"] = sep else: dc["sep"] = "" else: dc["sep"] = "" return dc soname_re = re.compile(r"(?P<basename>[\w\+]+([\.\-]+[\w\+]+)*)" r"\.so" r"(\.(?P<version>[\d\.]+))?" r"$") m = soname_re.match(soname) if not m: # There was no ".so" component, so it's hardo to figure out which one is # the name, but we'll try to figure out the numeric part of the soname. digits = "".join(re.findall(r"[0-9]+", soname)) alnum = "".join(re.findall(r"[a-zA-Z]+", soname)) parsed = { "basename": alnum, "version": digits, } else: parsed = m.groupdict() keywords_pkgname = {} keywords_catalogname = {}
(continued...)
for key in parsed: if parsed[key]: keywords_pkgname[key] = SonameToStringWithChar(parsed[key], "-") keywords_catalogname[key] = SonameToStringWithChar(parsed[key], "_") else: keywords_pkgname[key] = "" keywords_catalogname[key] = "" pkgname_list = [] keywords_pkgname = AddSeparator(keywords_pkgname, "-") pkgname_list.append( "CSW%(basename)s%(sep)s%(version)s" % keywords_pkgname) keywords_catalogname = AddSeparator(keywords_catalogname, "_") catalogname_list = [ "%(basename)s%(sep)s%(version)s" % keywords_catalogname, ] return pkgname_list, catalogname_list
Real life example
task: Index a list of dictionaries by one of the fields
def IndexBy(d_list, field_name): result = {} for d in d_list: result[d[field_name]] = d return result
import example_1
def main(): d = [{"foo": "a", "bar": "b"}, {"foo": "c", "bar": "d"}] print example_1.IndexBy(d, "foo")
if __name__ == '__main__': main()
import unittestimport example_1import pprint
class IndexByUnitTest(unittest.TestCase):
def testTwoElements(self): d = [{"foo": "a", "bar": "b"}, {"foo": "c", "bar": "d"}] pprint.pprint(example_1.IndexBy(d, "foo"))
if __name__ == '__main__': unittest.main()
import unittestimport example_1
class IndexByUnitTest(unittest.TestCase):
def testTwoElements(self): d = [{"foo": "a", "bar": "b"}, {"foo": "c", "bar": "d"}] expected = { 'a': {'foo': 'a', 'bar': 'b'}, 'c': {'foo': 'c', 'bar': 'd'}, } self.assertEquals(expected, example_1.IndexBy(d, "foo"))
if __name__ == '__main__': unittest.main()
blizinski@workstation ~/unit-test-talk $ python2.6 example_1_test.py .----------------------------------------------------------------------Ran 1 test in 0.000s
OK
Cultured way of playing with code
Changing your code
import unittestimport example_1
class IndexByUnitTest(unittest.TestCase):
def testTwoElements(self): d = [{"foo": "a", "bar": "b"}, {"foo": "c", "bar": "d"}, {"foo": "c", "bar": "e"}] expected = { 'a': {'foo': 'a', 'bar': 'b'}, 'c': {'foo': 'c', 'bar': 'd'}, } self.assertEquals(expected, example_1.IndexBy(d, "foo"))
if __name__ == '__main__': unittest.main()
task: Index a list of dictionaries by one of the fields
def IndexBy(d_list, field_name): result = {} for d in d_list: result.setdefault(d[field_name], []) result[d[field_name]].append(d) return result
Keeping a track record
def testMakePackageNameDashesNoDashes(self): soname = "libpyglib-2.0-python.so.0" expected = ( ['CSWlibpyglib2-0python0'], ['libpyglib2_0python0'], ) self.assertEqual(expected, su.MakePackageNameBySoname(soname))
def testMakePackageNameDashesNoDashesPython(self): soname = "libpython3.1.so.1.0" expected = ( ['CSWlibpython3-1-1-0'], ['libpython3_1_1_0'], ) self.assertEqual(expected, su.MakePackageNameBySoname(soname))
The trust issue
Your first steps in unit testing
Hug me, I only look alien!(never mind my boxing gloves)
It's about the waypieces of code
fit together
Your trust will gradually shift
Part of the development process
It's a tool which helps with some of the everyday tasks.
Further reading
http://en.wikipedia.org/wiki/Unit_testinghttp://diveintopython.org/unit_testing/index.htmlMock objects, stubs and fakes
ContactMaciej Bliziński <[email protected]>
References
Images:
http://commons.wikimedia.org/wiki/File:Pantheon_rome_inside_1-muniu.jpg by Muniuhttp://commons.wikimedia.org/wiki/File:Instant_miso_soup.jpg by Gleamhttp://www.flickr.com/photos/f-oxymoron/4203860207/sizes/l/in/photostream/ by f-oxymoronhttp://www.flickr.com/photos/jurvetson/1381322008/sizes/l/in/photostream/ by jurvetsonhttp://www.flickr.com/photos/7332902@N05/3221210836/ by David O'Driscollhttp://www.flickr.com/photos/edsweeney/4212380812/sizes/o/in/photostream/ by Ed Sweeney
http://www.flickr.com/photos/jenny-pics/3230153121/sizes/l/in/photostream/ by jenny downinghttp://www.flickr.com/photos/oskay/265899766/ by Windell Oskayhttp://www.flickr.com/photos/alismith44/357361903/ by Ali Westhttp://www.flickr.com/photos/cezaryborysiuk/3947857278/ by Cezary Borysiukhttp://www.flickr.com/photos/wilhei/109403331/ by wilhei55http://www.flickr.com/photos/antonymayfield/3221876089/ by antony_mayfieldhttp://www.flickr.com/photos/ralphandjenny/4999895776/ by Ralph Daily