[prev in list] [next in list] [prev in thread] [next in thread] 

List:       pykde
Subject:    [PyQt] Unit testing PyQt applications
From:       Mads Ipsen <madsipsen () gmail ! com>
Date:       2012-03-07 8:37:38
Message-ID: 4F571E52.2050107 () gmail ! com
[Download RAW message or body]

[Attachment #2 (multipart/alternative)]


Hi,

I have a general question about how to unit test PyQt applications using 
the Python unittest moudle. I have attached a few examples. If you have 
time to take a look and comment, it would be great.

The first module, Foo.py, defines a simple widget called 'Widget' which 
is tested in FooTest.py. FooTest.py defines an instance of a 
QApplication, which is needed in order to run the test. In this case the 
test runs fine.

The second module, Bar.py, defines a more complex widget, also called 
Widget, which starts a thread in its constructor. In real life, this 
could be a used for generating an icon in the background. This is tested 
in BarTest.py. In this case, the test fails, because the unittest exits 
while the thread is still running.

There are ways to circumvent this, e.g:

* Hook up a slot which gets called when the thread finishes
* Start the event loop by calling QtGui.qApp.exec_()
* Kill the event loop when the slot is called

But this easily becomes messy, when you have a large and complex code 
base, and I was wondering if there's some more generic approach.

I should add, that in my case I have a large nested unittest suite, 
which collects all the individual unittest files. In that case, the 
instance of a QApplication is only started once, by an __init__.py file, 
which gets loaded once, when the entire suite it run.

All that said, if you have any comments, pointers to good approaches, or 
like to share your ideas, I'd be happy to hear them.

Best regards,

Mads



-- 
+-----------------------------------------------------+
| Mads Ipsen                                          |
+----------------------+------------------------------+
| Gåsebæksvej 7, 4. tv |                              |
| DK-2500 Valby        | phone:          +45-29716388 |
| Denmark              | email:  mads.ipsen@gmail.com |
+----------------------+------------------------------+



[Attachment #5 (text/html)]

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>

    <meta http-equiv="content-type" content="text/html; charset=ISO-8859-1">
  </head>
  <body bgcolor="#ffffff" text="#000000">
    <font face="Consolas">Hi,<br>
      <br>
      I have a general question about how to unit test PyQt applications
      using the Python unittest moudle. I have attached a few examples.
      If you have time to take a look and comment, it would be great.<br>
      <br>
      The first module, Foo.py, defines a simple widget called 'Widget'
      which is tested in FooTest.py. FooTest.py defines an instance of a
      QApplication, which is needed in order to run the test. In this
      case the test runs fine.<br>
      <br>
      The second module, Bar.py, defines a more complex widget, also
      called Widget, which starts a thread in its constructor. In real
      life, this could be a used for generating an icon in the
      background. This is tested in BarTest.py. In this case, the test
      fails, because the unittest exits while the thread is still
      running. <br>
      <br>
      There are ways to circumvent this, e.g:<br>
      <br>
      * Hook up a slot which gets called when the thread finishes<br>
      * Start the event loop by calling QtGui.qApp.exec_()<br>
      * Kill the event loop when the slot is called<br>
      <br>
      But this easily becomes messy, when you have a large and complex
      code base, and I was wondering if there's some more generic
      approach.<br>
      <br>
      I should add, that in my case I have a large nested unittest
      suite, which collects all the individual unittest files. In that
      case, the instance of a QApplication is only started once, by an
      __init__.py file, which gets loaded once, when the entire suite it
      run.<br>
      <br>
      All that said, if you have any comments, pointers to good
      approaches, or like to share your ideas, I'd be happy to hear
      them.<br>
      <br>
      Best regards,<br>
      <br>
      Mads<br>
      <br>
      <br>
    </font><br>
    <pre class="moz-signature" cols="72">-- 
+-----------------------------------------------------+
> Mads Ipsen                                          |
+----------------------+------------------------------+
> G&aring;seb&aelig;ksvej 7, 4. tv |                              |
> DK-2500 Valby        | phone:          +45-29716388 |
> Denmark              | email:  <a class="moz-txt-link-abbreviated" \
> href="mailto:mads.ipsen@gmail.com">mads.ipsen@gmail.com</a> |
+----------------------+------------------------------+

</pre>
  </body>
</html>


["Foo.py" (text/x-python)]

from PyQt4 import QtGui

class Widget(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)


        
        

["FooTest.py" (text/x-python)]

import unittest
import sys
import gc

from PyQt4 import QtGui

# Must have an event handler running
QT_APP = QtGui.QApplication(sys.argv)

# Import the module that should be tested
from Foo import Widget

class ModelTest(unittest.TestCase):

    def setUp(self):
        self._widget = Widget()

    def tearDown(self):
        del self._widget
        gc.collect()

    def testWidget(self):
        """ Test that the object is OK """
        self.assertTrue(isinstance(self._widget, Widget))
        self.assertTrue(isinstance(self._widget, QtGui.QWidget))

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


["Bar.py" (text/x-python)]

import time

from PyQt4 import QtCore, QtGui

class Thread(QtCore.QThread):
    def __init__(self):
        QtCore.QThread.__init__(self)

    def run(self):
        for i in range(10):
            print i
            time.sleep(0.1)

class Widget(QtGui.QWidget):
    def __init__(self):
        QtGui.QWidget.__init__(self)
        self._thread = Thread()
        self._thread.start()
        self._finished = False

        self.connect(self._thread, QtCore.SIGNAL('finished'), self.finished)

    def finished(self):
        self._finished = True
        


        
        

["BarTest.py" (text/x-python)]

import unittest
import sys
import gc

from PyQt4 import QtGui

# Must have an event handler running
QT_APP = QtGui.QApplication(sys.argv)

# Import the module that should be tested
from Bar import Widget

class ModelTest(unittest.TestCase):

    def setUp(self):
        self._widget = Widget()

    def tearDown(self):
        del self._widget
        gc.collect()

    def testWidget(self):
        """ Test that the object is OK """
        self.assertTrue(isinstance(self._widget, Widget))
        self.assertTrue(isinstance(self._widget, QtGui.QWidget))

    def testThread(self):
        """ Test that the thread finished """
        self.assertTrue(self._widget._finished)

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



_______________________________________________
PyQt mailing list    PyQt@riverbankcomputing.com
http://www.riverbankcomputing.com/mailman/listinfo/pyqt

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic