2012-06-21 17 views
16

Estoy construyendo una aplicación basada en PySide 1.1.0, y he estado buscando buenos ejemplos para ver la unidad y pruebas funcionales de mi aplicación. Quiero poder realizar pruebas funcionales de la IU (simulando clics, pulsaciones de teclas, etc.), pruebas unitarias de las ranuras de UI que alteran el diseño de la IU (presumiblemente usando un remitente y receptor parcialmente burlado), así como la unidad prueba de código que implica widgets, pero sin requerir que se muestren ventanas.Unidad y prueba funcional una aplicación basada en PySide?

Como ejemplo, creo dinámicamente submenús de un menú en la barra de menú cuando se agrega un elemento a un modelo (objeto derivado de QAbstractItemModel) que proporciona datos a un QTreeView. El modelo y el submenú deben estar sincronizados, por lo que quiero poder escribir una prueba unitaria que envíe datos al controlador que administra el modelo y el submenú, y afirma que tanto el modelo como el submenú se actualizaron correctamente.

Preferiría NO tener que configurar una QApplication en mi código de prueba si puedo evitarlo. También me gustaría no tener que mostrar ninguna ventana cuando solo me importa validar estructuras de datos en widgets, no su visualización.

No encuentro nada de valor adecuado en http://www.pyside.org o en mis búsquedas de Google. ¿Alguien tiene alguna experiencia o sabe de un buen código de muestra que debería ver?

+0

También estoy muy intereseted en una solución para esto, ya que estoy frente a los mismos problemas exactos – Chris

+1

Ha visto: http : //johnnado.com/pyqt-qtest-example/ Es PyQt, pero más o menos lo mismo. – neuronet

Respuesta

29

He estado jugando un poco con el código pyside de pruebas unitarias y he llegado a la conclusión de que la combinación del módulo unittest de python con el módulo QTest de qt funciona bastante bien.

Deberá tener un objeto QApplication instanciado, pero no necesita ejecutar su método exec_, porque no necesita que se ejecute el bucle de evento.

Aquí es un ejemplo de cómo puedo probar si un QCheckBox en un cuadro de diálogo hace lo que se supone que debe hacer:

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

Esto funciona completamente fuera de la pantalla, implica clic widgets y escribir texto en un QLineEdit.

Así es como puedo probar un (bastante simple) 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 

espero que esto ayude un littlebit.

2

En mi caso, estaba obteniendo un error 'QPixmap: debe construir una QApplication before a QPaintDevice'.

Si necesita tener una instancia de QApplication para sus pruebas (por ejemplo, use QPixmap), esta es una forma de hacerlo. Simplemente cree un singleton para que tenga garantizada una única instancia de QApplication.

Esto está enterrado como un ayudante para las pruebas en la fuente 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() 

y luego UsesQApplication subclase

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) 

esperanza esto ayuda

+7

Acabo de hacer 'si QtGui.qApp == Ninguna: QtGui.QApplication ([]) 'al comienzo de cada módulo de prueba que usa QtGui. – strubbly