Sunday 31 January 2010

Lack of Testing: An Example

In my previous post I was saying how it's hard to test my code independently of the GUI Framework, since my application is heavily dependant upon the services it provides. Here's an example, exporting an image (which is represented in my program as a buffer that is drawn to)


Here's the basics:
- prompt user for location to export to.
- display a filedialog containing a file filter for image types
- check whether the given filetype is acceptable
- if there is no filetype present, append the currently selected file filter file extension
- save the data


def on_export(self, event=None):
"""Exports the current sheet as an image, or all as a PDF."""
filename = self.export_prompt()
if filename:
self.util.export(filename)


def export_prompt(self):
"""Returns the filename to save to"""
val = None # return value
wc = ("PNG (*.png)|*.png|JPEG (*.jpg, *.jpeg)|*.jpeg;*.jpg|" +
"BMP (*.bmp)|*.bmp|TIFF (*.tiff)|*.tiff")

dlg = wx.FileDialog(self, _("Export data to..."), style=wx.SAVE |
wx.OVERWRITE_PROMPT, wildcard=wc)
if dlg.ShowModal() == wx.ID_OK:
filename = dlg.GetPath()
_name = os.path.splitext(filename)[1].replace(".", "")
types = {0: "png", 1: "jpg", 2: "bmp", 3: "tiff"}

if not os.path.splitext(filename)[1]: # no extension
_name = types[dlg.GetFilterIndex()]
filename += "." + _name
val = filename
if not _name in meta.types[2:]:
wx.MessageBox(_("Invalid filetype to export as:")+" .%s" % _name,
_("Invalid filetype"))
else:
val = filename

dlg.Destroy()
return val


#------ the util.export() method:


def export(self, filename):
const = get_wx_image_type(filename)
self.gui.board.deselect()
self.gui.board.redraw_all()

context = wx.MemoryDC(self.gui.board.buffer)
memory = wx.MemoryDC()
x, y = self.gui.board.buffer.GetSize()
bitmap = wx.EmptyBitmap(x, y, -1)
memory.SelectObject(bitmap)
memory.Blit(0, 0, x, y, context, 0, 0)
memory.SelectObject(wx.NullBitmap)
bitmap.SaveFile(filename, const) # write to disk


def get_wx_image_type(filename):
"""
Returns the wx.BITMAP_TYPE_X for a given filename
"""
_name = os.path.splitext(filename)[1].replace(".", "").lower()

types = {"png": wx.BITMAP_TYPE_PNG, "jpg": wx.BITMAP_TYPE_JPEG, "jpeg":
wx.BITMAP_TYPE_JPEG, "bmp": wx.BITMAP_TYPE_BMP, "tiff":
wx.BITMAP_TYPE_TIF, "pcx": wx.BITMAP_TYPE_PCX }

return types[_name] # grab the right image type from dict. above


meta.types is a Python list of valid filetypes, e.g. ['jpg', 'png', 'bmp'...]

Now, sure, I could go in an test that given a particular filetype, the MessageBox is displayed (or not), or that entering no file name appends the correct extension.

The easiest way for me to test this is to draw a bunch of lines, and then try exporting it. I verify the file dialog appears, the file type filter works. I try selecting PNG, and typing in test. I see a file named test.png is created, I open it, it matches my image. I repeat the process, typing test2.png. File test2.png is created.

Writing mock GUI dialogs to return fake values and doing this in a TDD manner just seems like it wouldn't have helped much. I know there's a bit of code repeat (in get_wx_image_type) and this may not be the best example.

No comments:

Post a Comment