qtunittest.py

Go to the documentation of this file.
00001 # Qt Unit test module
00002 # (c) 2006 Werner Mayer
00003 #
00004 
00005 #***************************************************************************
00006 #*   (c) Werner Mayer <werner.wm.mayer@gmx.de> 2006                        *
00007 #*                                                                         *
00008 #*   This file is part of the FreeCAD CAx development system.              *
00009 #*                                                                         *
00010 #*   This program is free software; you can redistribute it and/or modify  *
00011 #*   it under the terms of the GNU Lesser General Public License (LGPL)    *
00012 #*   as published by the Free Software Foundation; either version 2 of     *
00013 #*   the License, or (at your option) any later version.                   *
00014 #*   for detail see the LICENCE text file.                                 *
00015 #*                                                                         *
00016 #*   FreeCAD is distributed in the hope that it will be useful,            *
00017 #*   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00018 #*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
00019 #*   GNU Library General Public License for more details.                  *
00020 #*                                                                         *
00021 #*   You should have received a copy of the GNU Library General Public     *
00022 #*   License along with FreeCAD; if not, write to the Free Software        *
00023 #*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  *
00024 #*   USA                                                                   *
00025 #*                                                                         *
00026 #*   Werner Mayer 2006                                                     *
00027 #***************************************************************************/
00028 
00029 __author__ = "Werner Mayer (werner.wm.mayer@gmx.de)"
00030 
00031 import string
00032 import traceback
00033 
00034 # Cannot import this file in case Python is not prepared for Tk.
00035 # Copy the needed classes instead.
00036 #import unittestgui
00037 
00038 import unittest
00039 import sys
00040 import traceback
00041 import string
00042 
00043 
00044 ##############################################################################
00045 # GUI framework classes
00046 # The classes BaseGUITestRunner, GUITestResult and RollbackImporter are
00047 # taken from the PyUnit framework written by Steve Purcell.
00048 # For more details see also http://pyunit.sourceforge.net.
00049 ##############################################################################
00050 
00051 class BaseGUITestRunner:
00052     """Subclass this class to create a GUI TestRunner that uses a specific
00053     windowing toolkit. The class takes care of running tests in the correct
00054     manner, and making callbacks to the derived class to obtain information
00055     or signal that events have occurred.
00056     """
00057     def __init__(self, *args, **kwargs):
00058         self.currentResult = None
00059         self.running = 0
00060         self.__rollbackImporter = None
00061         apply(self.initGUI, args, kwargs)
00062 
00063     def getSelectedTestName(self):
00064         "Override to return the name of the test selected to be run"
00065         pass
00066 
00067     def errorDialog(self, title, message):
00068         "Override to display an error arising from GUI usage"
00069         pass
00070 
00071     def runClicked(self):
00072         "To be called in response to user choosing to run a test"
00073         if self.running: return
00074         testName = self.getSelectedTestName()
00075         if not testName:
00076             self.errorDialog("Test name entry", "You must enter a test name")
00077             return
00078         if self.__rollbackImporter:
00079             self.__rollbackImporter.rollbackImports()
00080         self.__rollbackImporter = RollbackImporter()
00081         try:
00082             test = unittest.defaultTestLoader.loadTestsFromName(testName)
00083         except:
00084             exc_type, exc_value, exc_tb = sys.exc_info()
00085             apply(traceback.print_exception,sys.exc_info())
00086             self.errorDialog("Unable to run test '%s'" % testName,
00087                              "Error loading specified test: %s, %s" % \
00088                              (exc_type, exc_value))
00089             return
00090         self.currentResult = GUITestResult(self)
00091         self.totalTests = test.countTestCases()
00092         self.running = 1
00093         self.notifyRunning()
00094         test.run(self.currentResult)
00095         self.running = 0
00096         self.notifyStopped()
00097 
00098     def stopClicked(self):
00099         "To be called in response to user stopping the running of a test"
00100         if self.currentResult:
00101             self.currentResult.stop()
00102 
00103     # Required callbacks
00104 
00105     def notifyRunning(self):
00106         "Override to set GUI in 'running' mode, enabling 'stop' button etc."
00107         pass
00108 
00109     def notifyStopped(self):
00110         "Override to set GUI in 'stopped' mode, enabling 'run' button etc."
00111         pass
00112 
00113     def notifyTestFailed(self, test, err):
00114         "Override to indicate that a test has just failed"
00115         pass
00116 
00117     def notifyTestErrored(self, test, err):
00118         "Override to indicate that a test has just errored"
00119         pass
00120 
00121     def notifyTestStarted(self, test):
00122         "Override to indicate that a test is about to run"
00123         pass
00124 
00125     def notifyTestFinished(self, test):
00126         """Override to indicate that a test has finished (it may already have
00127            failed or errored)"""
00128         pass
00129 
00130 
00131 class GUITestResult(unittest.TestResult):
00132     """A TestResult that makes callbacks to its associated GUI TestRunner.
00133     Used by BaseGUITestRunner. Need not be created directly.
00134     """
00135     def __init__(self, callback):
00136         unittest.TestResult.__init__(self)
00137         self.callback = callback
00138 
00139     def addError(self, test, err):
00140         unittest.TestResult.addError(self, test, err)
00141         self.callback.notifyTestErrored(test, err)
00142 
00143     def addFailure(self, test, err):
00144         unittest.TestResult.addFailure(self, test, err)
00145         self.callback.notifyTestFailed(test, err)
00146 
00147     def stopTest(self, test):
00148         unittest.TestResult.stopTest(self, test)
00149         self.callback.notifyTestFinished(test)
00150 
00151     def startTest(self, test):
00152         unittest.TestResult.startTest(self, test)
00153         self.callback.notifyTestStarted(test)
00154 
00155 
00156 class RollbackImporter:
00157     """This tricky little class is used to make sure that modules under test
00158     will be reloaded the next time they are imported.
00159     """
00160     def __init__(self):
00161         self.previousModules = sys.modules.copy()
00162         
00163     def rollbackImports(self):
00164         for modname in sys.modules.keys():
00165             if not self.previousModules.has_key(modname):
00166                 # Force reload when modname next imported
00167                 del(sys.modules[modname])
00168 
00169 
00170 
00171 #---------------------------------------------------------------------------
00172 # Subclass of BaseGUITestRunner using Qt dialog
00173 #---------------------------------------------------------------------------
00174 
00175 
00176 class QtTestRunner(BaseGUITestRunner):
00177     """An implementation of BaseGUITestRunner using Qt.
00178     """
00179     def initGUI(self, root, initialTestName):
00180         """Set up the GUI inside the given root window. The test name entry
00181         field will be pre-filled with the given initialTestName.
00182         """
00183         self.root = root
00184         # Set up values that will be tied to widgets
00185         import QtUnitGui
00186         self.gui=QtUnitGui.UnitTest()
00187         self.gui.setStatusText("Idle")
00188         self.runCountVar = 0
00189         self.failCountVar = 0
00190         self.errorCountVar = 0
00191         self.remainingCountVar = 0
00192 
00193     def getSelectedTestName(self):
00194         return self.gui.getUnitTest()
00195 
00196     def errorDialog(self, title, message):
00197         return self.gui.errorDialog(title, message)
00198 
00199     def notifyRunning(self):
00200         self.runCountVar=0
00201         self.gui.setRunCount(0)
00202         self.failCountVar=0
00203         self.gui.setFailCount(0)
00204         self.errorCountVar=0
00205         self.gui.setErrorCount(0)
00206         self.remainingCountVar=self.totalTests
00207         self.gui.setRemainCount(self.totalTests)
00208         self.errorInfo = []
00209         self.gui.clearErrorList()
00210         self.gui.setProgressFraction(0.0)
00211         self.gui.updateGUI()
00212 
00213     def notifyStopped(self):
00214         self.gui.setStatusText("Idle")
00215 
00216     def notifyTestStarted(self, test):
00217         self.gui.setStatusText(str(test))
00218         self.gui.updateGUI()
00219 
00220     def notifyTestFailed(self, test, err):
00221         self.failCountVar=self.failCountVar+1
00222         self.gui.setFailCount(self.failCountVar)
00223         tracebackLines = apply(traceback.format_exception, err + (10,))
00224         tracebackText = string.join(tracebackLines,'')
00225         self.gui.insertError("Failure: %s" % test,tracebackText)
00226         self.errorInfo.append((test,err))
00227 
00228     def notifyTestErrored(self, test, err):
00229         self.errorCountVar=self.errorCountVar+1
00230         self.gui.setErrorCount(self.errorCountVar)
00231         tracebackLines = apply(traceback.format_exception, err + (10,))
00232         tracebackText = string.join(tracebackLines,'')
00233         self.gui.insertError("Error: %s" % test,tracebackText)
00234         self.errorInfo.append((test,err))
00235 
00236     def notifyTestFinished(self, test):
00237         self.remainingCountVar=self.remainingCountVar-1
00238         self.gui.setRemainCount(self.remainingCountVar)
00239         self.runCountVar=self.runCountVar+1
00240         self.gui.setRunCount(self.runCountVar)
00241         fractionDone = float(self.runCountVar)/float(self.totalTests)
00242         fillColor = len(self.errorInfo) and "red" or "green"
00243         self.gui.setProgressFraction(fractionDone, fillColor)

Generated on Wed Nov 23 19:00:35 2011 for FreeCAD by  doxygen 1.6.1