I've been looking for examples of how to run unit tests on a CGI.
Didn't find any so I came up with this pared down sample. Don't know
where to post example code so I figured I'd just email it to this
list. Perhaps it will be findable by others in the future.
This CGI with unit test examples takes three separate files to make it
work. Copy the example code into the files with the names provided and
put them all into the same directory.
In my current project, I have lots of unit tests for all the functions
I have created, but the main CGI code itself had no unit tests and it
really needed them. In this example, the CGI itself is a handful of
lines that should never change and the bulk of the processing is in a
function. This allows me to create unit tests on everything except the
few unchanging lines that are the generic CGI in the cgiRunner.py file.
Kee Nethery
---------- cgiRunner.py ------------
#!/usr/bin/env python
# 2009-11-17
# this is a simple CGI that is structured to allow for unit tests.
# this CGI responds to a GET or a POST
# send it anything and it will parrot it back along with client
# browser info.
# This sample has three files:
# cgiRunner.py this file
# cgiFunctions.py does the bulk of the CGI processing
# cgiUnitTest.py the unittest file for this CGI
# In this example, the bulk of the CGI processing occurs in a
# function. The function is in a separate file so that the
# unit tests can be run against it. All this main does is
# convert the URL parameters into a dictionary and
# feed that dictionary to the CGI function formatClientData()
# This is written for Python 2.6.x I'm using 2.6.4 and am trying to use
# code that works with Python 3.x and up.
import cgi ## so that I can be a web server CGI
import cgiFunctions ## where formatClientData() is located
def main():
# give me a list of all the user inputs posted to the cgi
formPostData = cgi.FieldStorage()
# and turn it into a key value pair dictionary
# this uses a list comprehension which I modelled after others
# examples. Normally I'd do a for loop but figured this
# should be as fast as possible.
formPostDict = dict((keyValue,formPostData[keyValue].value) \
for keyValue in formPostData)
# this is the call to the actual CGI code.
cgiResponseList = cgiFunctions.formatClientData(formPostDict)
# I like to return a list from functions so that I can put
# validity tests in the function. This one basically returns
# True if the GET or POST had any parameters sent to the
# CGI, False if none. Just an example.
if cgiResponseList[1] == True:
cgiResponseData = cgiResponseList[0]
else:
# if no parameters were sent to the CGI, the response
# describes how to add parameters to the URL that
# triggers this CGI.
cgiResponseData = cgiResponseList[0] + '\n\n' + 'The POST \
or GET you submitted had no user supplied parameters so other than \
client data. The only data that can be returned is the data \
provided by your web client. Most CGIs accept parameters and \
return results based upon those parameters. To provide GET data \
try adding a parameter like "sample=some_text". A URL with \
"sample" as a parameter (and sample2 as a second parameter) might \
look like \n"
http://machine.domain.com/cgi-bin/SimpleCgiUnittest.\
py?sample=some_text&sample2=more_text".'
# Python 3.x style print statement that works in Python 2.6.x
print('Content-type: text/html')
print('')
print(cgiResponseData)
main()
---------- cgiFunctions.py ------------
#!/usr/bin/env python
# 2009-11-17
import os ## gets the CGI client values like IP and URL
def formatClientData(formPostDict):
"""
This function contains the guts of the CGI response.
It is designed as a function so that I can use
unittest to test it.
"""
# create the output variable and then add stuff to it
cgiResponseData = ''
# I like to return lists from functions so that more than
# some kind of validity checking comes back from the
# function. In this case it's a lame validity check but
# it's an example.
hasFormPostData = (len(formPostDict) > 0)
# for something interesting to return, CGI client data
cgiResponseData = cgiResponseData + 'from client browser:\n'
for cgiKey in list(os.environ.keys()):
# for each client data value, add a line to the output
cgiResponseData = cgiResponseData + \
str(cgiKey) + ' = ' + os.environ[cgiKey] + '\n'
cgiResponseData = cgiResponseData + '\n\nfrom the URL \
POST or GET:\n\n'
# cycle through and output the POST or GET inputs
for keyValuePair in formPostDict:
cgiResponseData = cgiResponseData + \
keyValuePair + ' = ' + formPostDict[keyValuePair] + '\n'
return [cgiResponseData, hasFormPostData]
---------- cgiUnitTest.py ------------
#!/usr/bin/env python
import cgiFunctions
import unittest
class cgiTests(unittest.TestCase):
## For debugging of unit tests, to get one unit test
## to run first, UPPERCASE the first char of the unittext
## name (after "test_") so that it runs first then lower
## case it when it should be part of the group.
def setUp(self):
# this is for setting external stuff before unit tests
# this gets called before EVERY test
pass
def test_formatClientData_With(self):
inputDict = {'sample': 'test_text', 'drink': 'tea'}
cgiResponse = '''from the URL POST or GET:
sample = test_text
drink = tea
'''
expected0 = True
expected1 = True
outputList = cgiFunctions.formatClientData(inputDict)
outputBoolean0 = (cgiResponse in outputList[0])
self.assertEqual(outputBoolean0,expected0)
self.assertEqual(outputList[1],expected1)
def test_formatClientData_Without(self):
inputDict = {}
expected1 = False
outputList = cgiFunctions.formatClientData(inputDict)
self.assertEqual(outputList[1],expected1)
if __name__ == '__main__':
testSuite=unittest.TestLoader().loadTestsFromTestCase(cgiTests)
unittest.TextTestRunner(verbosity=2).run(testSuite)