Testing Framework for glideinWMS

Proposal

(by Justin, Igor)

PyUnit? is the industry standard for managing and executing Unit Tests on Python. It is based on the long tradition of the xUnit testing methodology/patterns, which started in Smalltalk but has quickly expanded to most modern programming languages.

Conveniently enough, PyUnit? has been included in the Python Standard Library since 2.1; the module is called "unittest". While there are many unit testing frameworks out there for Python, PyUnit? has often been found as one of the preferred ones.

As stated in this report <http://agiletesting.blogspot.com/2005/01/python-unit-testing-part-1-unittest.html>, here is a run-down of relevant Pros and Cons of PyUnit? :

unittest pros

  • available in the Python standard library
  • easy to use by people familiar with the xUnit frameworks
  • flexibility in test execution via command-line arguments
  • support for test fixture/state management via set-up/tear-down hooks
  • strong support for test organization and reuse via test suites

unittest Cons

  • xUnit flavor may be too strong for "pure" Pythonistas
  • API can get in the way and can make the test code intent hard to understand
  • tests can end up having a different look-and-feel from the code under test
  • tests are executed in alphanumerical order
  • assertions use custom syntax

I worked with xUnit in my past jobs and the framework is really an idea one for unit testing in general.

Attached is a quick unit test written up for xmlParse.py and xmlFormat.py, which fail intentionally to show how the output is formatted.

Traditionally, unit tests are stored in a directory in the root of the project, and checked into version control. Ideally, one file would be used per "unit" tested.

There are python frameworks available, such as nose, which work to manage and run series of tests and aggregate reports seamlessly.

Examples

Example 1

Sample testing code

import xmlFormat
import xmlParse
import os.path

import unittest

class TestSequenceFunctions(unittest.TestCase):
  
  # Is run before each test
  def setUp(self):
    
    self.test_file_path = "test.xml"
    self.test_xml_path = "test_xml.xml"
    
    self.test_dict = {"hello": "world", "okay": "go", "foo": "bar"}
    self.test_string = '\n   \n   \n   \n'
  
  
  #### TESTS ####
  
  def test_dict2string(self):
    # (I'm not 100% sure what dict_name or el_name should be)
    self.serialized_string = xmlFormat.dict2string(self.test_dict,"test_dict","key")
    
    # TEST: Assert that serialized_string is indeed a string
    self.assertTrue(isinstance(self.serialized_string,str))
    
    # TEST: Assert that each key and value pair is found in the string at least once
    for k, v in self.test_dict.items():
      self.assertTrue(self.serialized_string.find(k) > -1)
      self.assertTrue(self.serialized_string.find(v) > -1)
  
  def test_xmlstring2dict(self):
    # Input: Any valid, well-formed xml file representing a dict
    self.parsed_dict = xmlParse.xmlstring2dict(self.test_string)
    
    # TEST: Assert that parsed_dict is indeed a dict
    self.assertTrue(isinstance(self.parsed_dict,dict))
  
  def test_dict2file(self):
    self.f = open(self.test_file_path,"w")
    xmlFormat.dict2file(self.f,self.test_dict,"test_dict","key")
    self.f.close()
    
    # TEST: Assert that file exists
    self.assertTrue(os.path.isfile(self.test_file_path))
  
  def test_xmlfile2dict(self):
    self.parsed_dict = xmlParse.xmlfile2dict(self.test_xml_path)
    
    # TEST: Assert that parsed_dict is indeed a dict
    self.assertTrue(isinstance(self.parsed_dict,dict))
  
  
  
  # Testing serialization and parsing together
  
  def test_string_serialization(self):
    self.serialized_string = xmlFormat.dict2string(self.test_dict,"test_dict","key")
    self.parsed_dict = xmlParse.xmlstring2dict(self.serialized_string)
    
    # TEST: Assert that the original dict is equal to the parsed dict
    self.assertEqual(self.test_dict,self.parsed_dict)
    
    
  def test_xml_serialization(self):
    self.f = open(self.test_file_path,"w")
    xmlFormat.dict2file(self.f,self.test_dict,"test_dict","key")
    self.f.close()
    
    self.parsed_dict = xmlParse.xmlfile2dict(self.test_file_path)
    
    # TEST: Assert that the original dict is equal to the parsed dict
    self.assertEqual(self.test_dict,self.parsed_dict)

if __name__ == '__main__':
  unittest.main()

Sample Output

C:\Users\justin\Projects\Glidein\glideinWMS\lib>python xmlTest.py
..FF..
======================================================================
FAIL: test_string_serialization (__main__.TestSequenceFunctions)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "xmlTest.py", line 63, in test_string_serialization
    self.assertEqual(self.test_dict,self.parsed_dict)
AssertionError: {'foo': 'bar', 'okay': 'go', 'hello': 'world'} != {u'key': {u'name': u'okay', u'val': u'go'}}

======================================================================
FAIL: test_xml_serialization (__main__.TestSequenceFunctions)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "xmlTest.py", line 74, in test_xml_serialization
    self.assertEqual(self.test_dict,self.parsed_dict)
AssertionError: {'foo': 'bar', 'okay': 'go', 'hello': 'world'} != {u'key': {u'name': u'okay', u'val': u'go'}}

----------------------------------------------------------------------
Ran 6 tests in 0.169s

FAILED (failures=2)
#################### VERBOSE MODE ###################

C:\Users\justin\Projects\Glidein\glideinWMS\lib>python xmlTest.py -v
test_dict2file (__main__.TestSequenceFunctions) ... ok
test_dict2string (__main__.TestSequenceFunctions) ... ok
test_string_serialization (__main__.TestSequenceFunctions) ... FAIL
test_xml_serialization (__main__.TestSequenceFunctions) ... FAIL
test_xmlfile2dict (__main__.TestSequenceFunctions) ... ok
test_xmlstring2dict (__main__.TestSequenceFunctions) ... ok

======================================================================
FAIL: test_string_serialization (__main__.TestSequenceFunctions)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "xmlTest.py", line 63, in test_string_serialization
    self.assertEqual(self.test_dict,self.parsed_dict)
AssertionError: {'foo': 'bar', 'okay': 'go', 'hello': 'world'} != {u'key': {u'name': u'okay', u'val': u'go'}}

======================================================================
FAIL: test_xml_serialization (__main__.TestSequenceFunctions)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "xmlTest.py", line 74, in test_xml_serialization
    self.assertEqual(self.test_dict,self.parsed_dict)
AssertionError: {'foo': 'bar', 'okay': 'go', 'hello': 'world'} != {u'key': {u'name': u'okay', u'val': u'go'}}

----------------------------------------------------------------------
Ran 6 tests in 0.053s

FAILED (failures=2)
-- ParagMhashilkar - 2010/10/07
Topic revision: r1 - 2010/10/07 - 15:40:13 - ParagMhashilkar
 
This site is powered by the TWiki collaboration platformCopyright © by the contributing authors. All material on this collaboration platform is the property of the contributing authors.
Ideas, requests, problems regarding TWiki? Send feedback