2012-06-21 9 views
16

Ich baue eine PySide 1.1.0-basierte Anwendung und habe nach guten Beispielen gesucht, um meine Anwendung für Unit- und Funktionstests zu betrachten. Ich möchte in der Lage sein, Funktionsprüfung der Benutzeroberfläche (Simulation von Klicks, Tastendrücke, etc.), Unit-Tests von UI-Slots, die das Layout der Benutzeroberfläche (vermutlich mit einem teilweise verspotteten Sender und Empfänger), sowie Einheit Testen von Code, der Widgets enthält, ohne dass jedoch Fenster gerendert werden müssen.Unit- und Funktionstests einer PySide-basierten Anwendung?

Als ein Beispiel, ich dynamisch Untermenüs eines Menüs in der Menüleiste erstellen, wenn ein Element zu einem Modell (QAbstractItemModel abgeleitetes Objekt) hinzugefügt wird, die Daten zu einem QTreeView bereitstellt. Das Modell und das Untermenü müssen synchron bleiben. Daher möchte ich in der Lage sein, einen Komponententest zu schreiben, der Daten an den Controller übermittelt, der das Modell und das Untermenü verwaltet, und bestätigt, dass sowohl das Modell als auch das Untermenü ordnungsgemäß aktualisiert wurden.

Ich würde es vorziehen, keine QApplication in meinem Testcode einzurichten, wenn ich es vermeiden kann. Ich möchte auch keine Fenster anzeigen müssen, wenn es mir nur darum geht, Datenstrukturen in Widgets zu validieren, nicht ihre Visualisierung.

Ich kann nichts von geeignetem Wert bei http://www.pyside.org oder in meinen Google-Suchen finden. Hat jemand irgendwelche Erfahrung oder einen guten Beispielcode, den ich mir ansehen sollte?

+0

Ich bin auch in einer Lösung für diese sehr intereseted, wie ich genau die gleichen Probleme, denen ich – Chris

+1

Sie gesehen haben: http : //johnnado.com/pyqt-qtest-example/ Es ist PyQt, aber ziemlich genau so. – neuronet

Antwort

29

Ich habe jetzt ein bisschen mit Unit-Testing pyside Code gespielt und kam zu der Schlussfolgerung, dass die Kombination unittest Modul von Python mit Qt QTest Modul ziemlich gut funktioniert.

Sie müssen ein QApplication Objekt instanziiert haben, aber Sie müssen nicht seine exec_ Methode ausführen, da Sie die Ereignisschleife nicht ausgeführt werden müssen.

Hier ist ein Beispiel dafür, wie ich testen, ob ein QCheckBox in einem Dialog das tut, was es tun soll:

class Test_PwsAddEntryDialog(TestCase): 
    """Tests the class PwsAddEntryDialog.""" 

    def test_password_strength_checking_works(self): 
     """Tests if password strength checking works, if the corresponding check 
     box is checked. 
     """ 
     d = PwsAddEntryDialog() 
     # test default of internal flag 
     self.assertFalse(d.testPasswordStrength) 
     # type something 
     QTest.keyClicks(d.editSecret, "weak", 0, 10) 
     # make sure that entered text is not treated as a password 
     self.assertEqual(d.labelPasswordStrength.text(), "") 
     # click 'is password' checkbox 
     QTest.mouseClick(d.checkIsPassword, Qt.LeftButton) 
     # test internal flag changed 
     self.assertTrue(d.testPasswordStrength) 
     # test that label now contains a warning 
     self.assertTrue(d.labelPasswordStrength.text().find("too short") > 0) 
     # click checkbox again 
     QTest.mouseClick(d.checkIsPassword, Qt.LeftButton) 
     # check that internal flag once again changed 
     self.assertFalse(d.testPasswordStrength) 
     # make sure warning disappeared again 
     self.assertEqual(d.labelPasswordStrength.text(), "") 

Das funktioniert völlig Off-Screen beinhaltet Widgets und Eingabe von Text in einem QLineEdit klicken.

Hier ist, wie ich eine (ziemlich einfach) testen QAbstractListModel:

class Test_SectionListModel(TestCase): 
    """Tests the class SectionListModel.""" 

    def test_model_works_as_expected(self): 
     """Tests if the expected rows are generated from a sample pws file 
     content. 
     """ 
     model = SectionListModel(SAMPLE_PASSWORDS_DICT) 
     l = len(SAMPLE_PASSWORDS_DICT) 
     self.assertEqual(model.rowCount(None), l) 
     i = 0 
     for section in SAMPLE_PASSWORDS_DICT.iterkeys(): 
      self.assertEqual(model.data(model.index(i)), section) 
      i += 1 

Ich hoffe, dass dies ein littlebit hilft.

2

In meinem Fall bekam ich einen Fehler 'QPixmap: Muss eine QApplication vor einem QPaintDevice erstellen'.

Wenn Sie eine QApplication-Instanz für Ihre Tests benötigen (z. B. QPixmap verwenden), können Sie dies wie folgt tun. Erstellen Sie einfach ein Singleton, so dass Ihnen nur eine einzige QApplication-Instanz zur Verfügung steht.

Dies ist als ein Helfer für Tests in der PySide-Quelle begraben.

import unittest 

from PySide.QtGui import QApplication 
_instance = None 

class UsesQApplication(unittest.TestCase): 
    '''Helper class to provide QApplication instances''' 

    qapplication = True 

    def setUp(self): 
     '''Creates the QApplication instance''' 

     # Simple way of making instance a singleton 
     super(UsesQApplication, self).setUp() 
     global _instance 
     if _instance is None: 
      _instance = QApplication([]) 

     self.app = _instance 

    def tearDown(self): 
     '''Deletes the reference owned by self''' 
     del self.app 
     super(UsesQApplication, self).tearDown() 

und dann Unterklasse UsesQApplication

from PySide import QtGui 

class Test(UsesQApplication): 

    def setUp(self): 
     #If you override setup, tearDown, make sure 
     #to have a super call 
     super(TestFilterListItem, self).setUp() 

    def tearDown(self): 
     super(TestFilterListItem, self).tearDown() 

    def testName(self): 
     pix = QtGui.QPixmap(20,20) 
     self.assertTrue(True) 

hoffe, das hilft

+7

Ich mache nur 'wenn QtGui.qApp == Keine: QtGui.QApplication ([]) 'zu Beginn jedes Testmoduls, das QtGui verwendet. – strubbly

Verwandte Themen