Unit testing

 For those seeking instant
       gratification
Maciej Bliziński <blizinski@google.com>
       Python Ireland 2010-11-10
Helps the design
Provides live documentation
Helps 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):                                          (continued...)
 """Find the package name based on the soname.
                                                                               for key in parsed:
 Returns a pair of pkgname, catalogname.                                         if parsed[key]:
 """                                                                               keywords_pkgname[key] = SonameToStringWithChar(parsed[key], "-")
 def AddSeparator(d, sep):                                                         keywords_catalogname[key] = SonameToStringWithChar(parsed[key], "_")
   """Adds a separator based on the neighboring                                  else:
   of two digits."""                                                               keywords_pkgname[key] = ""
   dc = copy.copy(d)                                                               keywords_catalogname[key] = ""
   if dc["version"]:                                                           pkgname_list = []
     if (dc["basename"][-1].isdigit()                                          keywords_pkgname = AddSeparator(keywords_pkgname, "-")
        and                                                                    pkgname_list.append(
        dc["version"][0].isdigit()):                                               "CSW%(basename)s%(sep)s%(version)s" % keywords_pkgname)
       dc["sep"] = sep                                                         keywords_catalogname = AddSeparator(keywords_catalogname, "_")
     else:                                                                     catalogname_list = [
       dc["sep"] = ""                                                              "%(basename)s%(sep)s%(version)s" % keywords_catalogname,
   else:                                                                       ]
     dc["sep"] = ""                                                            return pkgname_list, catalogname_list
   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 = {}




                                                                                                           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 unittest
import example_1
import 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 unittest
import 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 unittest
import 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 way
  pieces 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_testing
  http://diveintopython.org/unit_testing/index.html
  Mock objects, stubs and fakes


Contact
         Maciej Bliziński <blizinski@google.com>
References

Images:

      http://commons.wikimedia.org/wiki/File:Pantheon_rome_inside_1-muniu.jpg by Muniu
      http://commons.wikimedia.org/wiki/File:Instant_miso_soup.jpg by Gleam
      http://www.flickr.com/photos/f-oxymoron/4203860207/sizes/l/in/photostream/ by f-oxymoron
      http://www.flickr.com/photos/jurvetson/1381322008/sizes/l/in/photostream/ by jurvetson
      http://www.flickr.com/photos/7332902@N05/3221210836/ by David O'Driscoll
      http://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 downing
      http://www.flickr.com/photos/oskay/265899766/ by Windell Oskay
      http://www.flickr.com/photos/alismith44/357361903/ by Ali West
      http://www.flickr.com/photos/cezaryborysiuk/3947857278/ by Cezary Borysiuk
      http://www.flickr.com/photos/wilhei/109403331/ by wilhei55
      http://www.flickr.com/photos/antonymayfield/3221876089/ by antony_mayfield
      http://www.flickr.com/photos/ralphandjenny/4999895776/ by Ralph Daily

Python Ireland Nov 2010 Talk: Unit Testing

  • 1.
    Unit testing Forthose seeking instant gratification Maciej Bliziński <blizinski@google.com> Python Ireland 2010-11-10
  • 2.
    Helps the design Provideslive documentation Helps refactoring
  • 3.
    But I'm hungryright now!
  • 4.
    I love tosee my code run
  • 6.
    task: Index alist 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
  • 7.
    def MakePackageNameBySoname(soname): (continued...) """Find the package name based on the soname. for key in parsed: Returns a pair of pkgname, catalogname. if parsed[key]: """ keywords_pkgname[key] = SonameToStringWithChar(parsed[key], "-") def AddSeparator(d, sep): keywords_catalogname[key] = SonameToStringWithChar(parsed[key], "_") """Adds a separator based on the neighboring else: of two digits.""" keywords_pkgname[key] = "" dc = copy.copy(d) keywords_catalogname[key] = "" if dc["version"]: pkgname_list = [] if (dc["basename"][-1].isdigit() keywords_pkgname = AddSeparator(keywords_pkgname, "-") and pkgname_list.append( dc["version"][0].isdigit()): "CSW%(basename)s%(sep)s%(version)s" % keywords_pkgname) dc["sep"] = sep keywords_catalogname = AddSeparator(keywords_catalogname, "_") else: catalogname_list = [ dc["sep"] = "" "%(basename)s%(sep)s%(version)s" % keywords_catalogname, else: ] dc["sep"] = "" return pkgname_list, catalogname_list 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 = {} Real life example
  • 8.
    task: Index alist 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
  • 9.
    import example_1 def main(): d = [{"foo": "a", "bar": "b"}, {"foo": "c", "bar": "d"}] print example_1.IndexBy(d, "foo") if __name__ == '__main__': main()
  • 10.
    import unittest import example_1 importpprint 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()
  • 11.
    import unittest import example_1 classIndexByUnitTest(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()
  • 12.
    blizinski@workstation ~/unit-test-talk $python2.6 example_1_test.py . ---------------------------------------------------------------------- Ran 1 test in 0.000s OK
  • 13.
    Cultured way ofplaying with code
  • 14.
  • 15.
    import unittest import example_1 classIndexByUnitTest(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()
  • 17.
    task: Index alist 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
  • 18.
  • 19.
    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))
  • 20.
    The trust issue Yourfirst steps in unit testing
  • 21.
    Hug me, Ionly look alien! (never mind my boxing gloves)
  • 23.
    It's about theway pieces of code fit together
  • 24.
    Your trust willgradually shift
  • 25.
    Part of thedevelopment process
  • 26.
    It's a toolwhich helps with some of the everyday tasks.
  • 27.
    Further reading http://en.wikipedia.org/wiki/Unit_testing http://diveintopython.org/unit_testing/index.html Mock objects, stubs and fakes Contact Maciej Bliziński <blizinski@google.com>
  • 28.
    References Images: http://commons.wikimedia.org/wiki/File:Pantheon_rome_inside_1-muniu.jpg by Muniu http://commons.wikimedia.org/wiki/File:Instant_miso_soup.jpg by Gleam http://www.flickr.com/photos/f-oxymoron/4203860207/sizes/l/in/photostream/ by f-oxymoron http://www.flickr.com/photos/jurvetson/1381322008/sizes/l/in/photostream/ by jurvetson http://www.flickr.com/photos/7332902@N05/3221210836/ by David O'Driscoll http://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 downing http://www.flickr.com/photos/oskay/265899766/ by Windell Oskay http://www.flickr.com/photos/alismith44/357361903/ by Ali West http://www.flickr.com/photos/cezaryborysiuk/3947857278/ by Cezary Borysiuk http://www.flickr.com/photos/wilhei/109403331/ by wilhei55 http://www.flickr.com/photos/antonymayfield/3221876089/ by antony_mayfield http://www.flickr.com/photos/ralphandjenny/4999895776/ by Ralph Daily