Unit testing with PyUnit
For much greater detail, check out the Python UnitTest Documentation
Python's unittest module provides a framework for automated unit testing (based on the Java unit test framework).
In essence, you create a class for each of a collection of test sets, following the naming and inheritance conventions described in the code example below, and you can then automatically run all test cases from each of the test sets.
Here is a simple example:
#! /usr/bin/env python
# ==========================================================
# Set up paths and import all necessary components
#
# import the system module and python's unit testing module
import sys, unittest
# import the module to be tested
from MyPythonDotpyFileToBeTested import *
# set up a simple test class
class TestSetOne(unittest.TestCase):
def setUp(self):
"""Automatically called to set up each test case below"""
# do whatever you want to set things up before these test cases
print "setting up a test from set one"
def tearDown(self):
"""Automatically called to clean up after each test case below"""
# do whatever you want to clean things up
print "cleaning up a test from set one"
def testA(self):
"""Test case names MUST begin with the word test"""
print "test A"
def testB(self):
"""Test case ordering is alphabetic by method name"""
print "test B"
class TestSetTwo(unittest.TestCase):
def setUp(self):
"""Automatically called to set up each test case below"""
# do whatever you want to set things up before these test cases
print "setting up a test from set two"
def tearDown(self):
"""Automatically called to clean up after each test case below"""
# do whatever you want to clean things up
print "cleaning up a test from set two"
def test2(self):
"""Test case names MUST begin with the word test"""
print "test2"
def test1(self):
"""Test case ordering is alphabetic by method name"""
print "test1"
# run all tests from all sets
if __name__ == "__main__":
unittest.main()
Python and MySQL
Method 1 (Hack)
If one doesn't have access to a Python interface for the database you want to use, you can use python's getoutput command to run a Unix/Linux command and capture the resulting output as a string.
For instance, we can use the popen command in the os module to run a linux/unix command, and store the results in a variable. We can then use the readline() command to step through these stored results one line of output at a time, e.g.:
import os
results = os.popen("some command", "r", 100)
nextline = results.readline()
print nextline
|
If we are interested in running a MySQL query, then our command might be built and executed something like
#! /usr/bin/env python import os executable = "/usr/local/mysql/bin/mysql" user = "wesselsd" password = "something clever" hostname = "localhost" sqlcommand = "\"show databases;\"" cmd = executable + " -u" + user + " -p" + password + " -e" + sqlcommand; result = os.popen(cmd, "r") for nextline in result.readlines(): print nextline |
Method 2 (Cleaner)
The standard method to access a MySQL database in a python script uses the MySQLdb module to establish a connection to the database, and then creates a cursor through which to access the database.
With that set up (see the example below) one can runn selects, inserts, etc using the cursor execute method.
When doing selects, we usually retrieve multiple rows, each with multiple columns
of data.
The collection of rows can be retrieved using the fetchall() method,
and then accessed one at a time using a for-in loop, as illustrated below. Note that
each row will be an array of multiple strings (one per column).
When doing inserts, it is probably easiest to use the triple-double quoted strings approach to prevent our insertion string from being parsed by Python before it gets to the database. Again, see the example below.
import MySQLdb
# connect to the db and obtain a cursor
db = MySQLdb.connect(host="localhost", user="joe", passwd="secret", db="databasename")
cursor = db.cursor()
# example of running a select statement and parsing the results
cursor.execute("SELECT * FROM *")
result = cursor.fetchall()
for record in result:
# print the fields of the record
print record[0],record[1], etc
# example of running an insert statement
cursor.execute("""INSERT INTO tablename (colname, colname) VALUES ("BLAH", "BLAH")""")
|
Tkinter is a Python interface to the Tk GUI toolkit, and is a quick and effective way to put together user interfaces. Unfortunately, the current Python configurations on csciun1 don't support it, but if you want to experiment with it in the windows labs or at home then the following are good introductory tutorials:
For now simply import the whole thing, e.g.The basic process in creating GUI elements with this module is
A simple example is shown first:
# import the necessary modules
from Tkinter import *
# display a message in the python control console
print "This is the control console, please watch the GUI instead!"
# set up the root, or outermost window
root = Tk()
root.title("Hello World Window")
# create the components (widgets) within the root
# and set the placement of each within the loop
# a clickable button
firstbutton = Button(root, text = "Click me")
firstbutton.grid()
# a labelled data entry field
firstlabel = Label(root, text="Userid:")
firstlabel.grid()
username = Entry(root, width=20)
username.grid()
# start the root window running
root.mainloop()
|
To do so, we have to revise our approach somewhat, and will derive our GUI classes from Tkinter's Frame class.
A simple class-based GUI is shown below:
# make sure we import the necessary GUI components
from Tkinter import *
# ==========================================================
# win_Example class: The Central Example Window
#
# note this is inheriting from Tkinter's Frame class
#
class WinExample(Frame):
# constructor for the main window
def __init__(self, master=None):
# call the Frame class constructor
Frame.__init__(self, master)
# call the createWidgets method
# to add all the other parts of this window
self.createWidgets()
# method to add widgets to the main window
def createWidgets(self):
self.add_HelpButton()
# method to add a help button
def add_HelpButton(self):
# create the button
self.HelpButton = Button(self)
# set the button's options
self.HelpButton["text"] = "Help",
# place the button within the window
self.HelpButton.grid()
# ==========================================================
# Main Routine
#
app = WinExample()
app.master.title("Example master title")
app.mainloop()
|
A more extensive class-based GUI is shown below, and will be discussed next week:
# ==========================================================
# Set up paths and import all necessary components
#
# make sure we import the necessary GUI components
from Tkinter import *
# ==========================================================
# win_Example class: The Central Example Window
#
# note this is inheriting from Tkinter's Frame class
#
class WinExample(Frame):
# ---------------------------------------
# Constructors
#
# constructor for the main window
def __init__(self, master=None):
# call the Frame class constructor
Frame.__init__(self, master)
# place the current window within its parent
# and make it resizable
self.grid(sticky=N+S+E+W)
# call the createWidgets method
# to add all the other parts of this window
self.createWidgets()
# ---------------------------------------
# Widgets
#
# method to add widgets to the main example window
def createWidgets(self):
self.add_HelpButton()
self.addTitles()
self.add_ReportButton()
self.add_LoadButton()
self.add_SaveButton()
# now make all the rows and columns resizable
top = self.winfo_toplevel()
top.rowconfigure(0,weight=1)
top.columnconfigure(0,weight=1)
self.columnconfigure(0,weight=1)
self.columnconfigure(1,weight=1)
self.columnconfigure(2,weight=1)
self.rowconfigure(0,weight=1)
self.rowconfigure(1,weight=1)
self.rowconfigure(2,weight=1)
self.rowconfigure(3,weight=1)
self.rowconfigure(4,weight=1)
# method to add a help button
def add_HelpButton(self):
# create the button
self.HelpButton = Button(self)
# set the button's options
self.HelpButton["text"] = "Help",
self.HelpButton["bg"] = "LightBlue",
# bind pressing the button to the write_to_console method
self.HelpButton["command"] = self.spawn_help_window
# place the button within the window
self.HelpButton.grid(row=1,column=0,sticky=N+S+E+W,padx=2,pady=2)
# method to add a title label and a description label
def addTitles(self):
# create the title button
self.TitleSection = Label(self)
# set the label's options
self.TitleSection["text"] = "Example",
self.TitleSection["bg"] = "black",
self.TitleSection["fg"] = "white",
# bind keyclicks over the title to the about window
self.TitleSection.bind(' |