2012-06-21 13 views
16

Sto costruendo un'applicazione basata su PySide 1.1.0 e sono alla ricerca di buoni esempi per verificare l'unità e il test funzionale della mia applicazione. Voglio essere in grado di eseguire test funzionali dell'interfaccia utente (simulando clic, pressioni dei tasti, ecc.), Test delle unità degli slot dell'interfaccia utente che alterano il layout dell'interfaccia utente (presumibilmente utilizzando un mittente e un ricevitore parzialmente derisi), oltre all'unità test del codice che coinvolge i widget, ma senza richiedere il rendering di finestre.Test funzionali e unitari di un'applicazione basata su PySide?

Come esempio, dinamicamente creo sottomenu di un menu nella barra dei menu quando un elemento viene aggiunto a un modello (oggetto derivato da QAbstractItemModel) che fornisce dati a un QTreeView. Il modello e il sottomenu devono rimanere sincronizzati, quindi voglio essere in grado di scrivere un test unitario che inoltra i dati al controller che gestisce il modello e il sottomenu e afferma che sia il modello che il sottomenu sono stati aggiornati correttamente.

Preferisco NON impostare un QApplicazione nel mio codice di test se posso evitarlo. Vorrei anche non dover visualizzare alcuna finestra quando mi interessa solo convalidare le strutture dati nei widget, non la loro visualizzazione.

Non riesco a trovare nulla di valore adatto a http://www.pyside.org o nelle mie ricerche di Google. Qualcuno ha qualche esperienza o sa di buon codice di esempio che dovrei guardare?

+0

Sto anche altamente interessare anche una soluzione per questo, come io sto affrontando gli stessi problemi esatti – Chris

+1

hai visto: http : //johnnado.com/pyqt-qtest-example/ È PyQt, ma più o meno lo stesso. – neuronet

risposta

29

Ho giocato un po 'intorno ora con unit test del codice PySide e sono giunto alla conclusione che la combinazione del modulo di Python unittest con il modulo di qt QTest funziona piuttosto bene.

È necessario disporre di un oggetto QApplication istanziato, ma non è necessario eseguire il suo metodo exec_, perché non è necessario che il ciclo di eventi sia in esecuzione.

Ecco un esempio di come ho test se un QCheckBox in una finestra fa quello che deve fare:

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(), "") 

Questo funziona completamente fuori dallo schermo, coinvolge cliccando widget e digitando il testo in un QLineEdit.

ecco come lo prova un (piuttosto semplice) 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 

Spero che questo aiuta un littlebit.

2

Nel mio caso, ho ricevuto un errore "QPixmap: deve creare una QApplicazione prima di un QPaintDevice".

Se è necessario disporre di un'istanza QApplication per i test (ad esempio, utilizzare QPixmap), ecco un modo per farlo. Basta creare un singleton in modo da garantire una sola istanza di QApplication.

Questo è sepolto come aiuto per i test nella sorgente PySide.

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() 

e poi UsesQApplication sottoclasse

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) 

speranza che questo aiuta

+7

Faccio solo "se QtGui.qApp == Nessuno: QtGui.QApplication ([]) 'all'inizio di ogni modulo di test che utilizza QtGui. – strubbly