1

I have a wxpython dialog which raises a TypeError exception when clicking the OK button. I would like to test the occurrence of the exception with unittest but the test does not work as expected. The output shows that the exception is raised. Anyhow unittest notifies that the test fails:

"C:\Program Files (x86)\Python\python.exe" test.py
Traceback (most recent call last):
  File "test.py", line 22, in on_ok
    raise TypeError( 'TypeError raised' )
TypeError: TypeError raised
F
======================================================================
FAIL: test_should_raise (__main__.CDlgTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "test.py", line 34, in test_should_raise
    self._dut.m_button_ok.GetEventHandler().ProcessEvent( event )
AssertionError: TypeError not raised

----------------------------------------------------------------------
Ran 1 test in 0.005s

FAILED (failures=1)

Here is a reduced sample of my code:

import unittest
import wx

class CDlgBase ( wx.Dialog ):
    """The UI"""
    def __init__( self, parent ):
        wx.Dialog.__init__ ( self, parent )
        bSizerTest = wx.BoxSizer( wx.VERTICAL )
        self.m_button_ok = wx.Button( self, wx.ID_ANY )
        bSizerTest.Add( self.m_button_ok, 0 )
        self.SetSizer( bSizerTest )
        # Connect Events
        self.m_button_ok.Bind( wx.EVT_BUTTON, self.on_ok )
    def on_ok( self, event ):
        event.Skip()

class CDlg( CDlgBase ) :
    """The dialog"""
    def __init__(self, parent):
        super( CDlg, self).__init__(parent)
    def on_ok(self, event):
        # The exception should be verified in the test `test_should_raise()`.
        raise TypeError( 'TypeError raised' )

class CDlgTest( unittest.TestCase ) :
    """The test class"""
    def setUp(self):
        self._dut = CDlg(None)
    def test_should_raise(self):
        """The test to verify raising the TypeError exception in the event 
        method `on_ok()`. this is the test method wich works not as expected."""
        event = wx.CommandEvent( wx.EVT_BUTTON.evtType[0] )
        event.SetEventObject( self._dut.m_button_ok )
        with self.assertRaises( TypeError ) :
            """Simulate an "OK" click. `on_ok()` will be executed 
            and raises the TypeError exception."""
            self._dut.m_button_ok.GetEventHandler().ProcessEvent( event )

if __name__ == '__main__':
    app = wx.App()
    tests = [ unittest.TestLoader().loadTestsFromTestCase( CDlgTest) ]
    unittest.TextTestRunner(verbosity=2, failfast=True).run(unittest.TestSuite(tests) )

Can somebody please help me to find out what I did wrong?

Humbalan
  • 677
  • 3
  • 14
  • I am myself curious for a solution to this. To my understanding, the exception is raised in another thread and caught by the wx framework, probably its trace dumped to `stdout`. – Dr. V Nov 08 '16 at 09:23
  • From another python forum I received the following answer: This is a general problem in testing a GUI. Exceptions thrown in event handlers should not have influence to the complete program. This is the reason while the scheduler catches them and does not forward them to your test routine. Event handlers should be not more than thin layers which should be tested separately without the GUI. – Humbalan Nov 08 '16 at 17:54

1 Answers1

2

See: https://wiki.wxpython.org/CppAndPythonSandwich

Exceptions are not passed up the call stack though the C++ layers. When control returns to C++ from Python then it checks if there was a Python exception that was not caught, if so then it prints and then clears the error.

One way to deal with this in unit tests is to catch the exception in your event handler, and set a flag. Then back in the test code you can check for that flag being set or not.

RobinDunn
  • 6,116
  • 1
  • 15
  • 14
  • I tried your advice an it works for me. Thanks a lot. Anyhow I am thinking about redisigning my validators to work without exceptions. – Humbalan Nov 09 '16 at 07:57