Модульное и функциональное тестирование приложения на основе PySide?

Я создаю приложение на основе PySide 1.1.0 и ищу хорошие примеры для модульного и функционального тестирования моего приложения. Я хочу иметь возможность выполнять функциональное тестирование пользовательского интерфейса (имитация щелчков, нажатие клавиш и т. Д.), Модульное тестирование слотов пользовательского интерфейса, которые изменяют макет пользовательского интерфейса (предположительно с использованием частично смоделированного отправителя и получателя), а также модуля тестирование кода с использованием виджетов, но без необходимости рендеринга окон.

В качестве одного примера, я динамически создаю подменю одного меню в строке меню, когда элемент добавляется в модель (объект, производный от QAbstractItemModel), который предоставляет данные для QTreeView. Модель и подменю должны оставаться синхронизированными, поэтому я хочу иметь возможность написать модульный тест, который передает данные в контроллер, который управляет моделью и подменю, и утверждает, что и модель, и подменю были должным образом обновлены.

Я бы предпочел НЕ устанавливать QApplication в моем тестовом коде, если я могу избежать этого. Я также хотел бы, чтобы мне не приходилось отображать какие-либо окна, когда меня интересует только проверка структур данных в виджетах, а не их визуализация.

Я не могу найти ничего подходящего на http://www.pyside.org/ или в моих поисках в Google. Кто-нибудь имеет опыт или знает хороший пример кода, на который я должен смотреть?

2 ответа

Решение

Сейчас я немного поигрался с модульным тестированием pyside-кода и пришел к выводу, что объединение Python unittest модуль с QT QTest Модуль работает довольно хорошо.

Вам нужно будет иметь QApplication объект создан, но вам не нужно запускать его exec_ метод, потому что вам не нужен цикл обработки событий.

Вот пример того, как я тестирую, если QCheckBox в диалоге делает то, что должен делать:

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

Это полностью работает за пределами экрана, включает в себя нажатие виджетов и ввод текста в QLineEdit,

Вот как я тестирую (довольно просто) 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

Я надеюсь, что это помогает немного.

В моем случае я получал сообщение об ошибке "QPixmap: необходимо создать QApplication перед QPaintDevice".

Если вам нужен экземпляр QApplication для ваших тестов (например, используйте QPixmap), вот один из способов сделать это. Просто создайте одноэлементный файл, чтобы обеспечить вам один и только один экземпляр QApplication.

Это похоронено как помощник для тестов в источнике 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()

а затем подкласс 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)

надеюсь это поможет

Другие вопросы по тегам