Каков рекомендуемый способ тестирования приложений Python с графическим интерфейсом?

В настоящее время я достаточно глуп, чтобы пытаться поддерживать две параллельные базы кода для настольного приложения Python, одну с использованием интроспекции PyGObject для GTK 3, а другую с использованием PyGTK для GTK 2. В основном я работаю над ветвью PyGObject, а затем переношу изменения в Филиал PyGTK. Из-за всех незначительных различий между этими реализациями я часто упускаю из виду вещи и вызываю поломки, которые я пропускаю и случайно выпускаю, только для того, чтобы их поймали пользователи.

Я пытаюсь найти хороший способ разработки некоторых модульных тестов, которые предпочтительно подходят для запуска на обеих базах кода. Это не слишком сложная программа (по сути, это инструмент управления библиотекой, представьте себе, как iTunes):

- Main Window
  |- Toolbar with some buttons (add/edit/remove items, configure the program)
  |
  |- VPaned
  |--- Top HPaned
  |------ ListView (listing values by which a library of items can be filtered)
  |------ ListView (listing the contents of the library
  |--- Bottom HPaned
  |------ Image (displaying cover art for the currently selected item in the library)
  |------ TextView (displaying formatted text describing the currently selected item)
 - Edit dialog
 - Configuration dialog
 - About dialog 

Я пытался максимально отделить виды от моделей. Каждый из этих элементов реализован в своем собственном классе (ну, в классах, которые наследуются от перечисленных классов GTK). ListViews связаны с другими классами, которые наследуются от ListStores. Сама библиотека обрабатывается другим классом. Тем не менее, существуют взаимодействия между виджетами, которые необходимо протестировать. Например, если пользователь выбирает конкретный элемент в представлении фильтра, фильтруя библиотеку, а затем выбирает элемент из отфильтрованных результатов, текстовое представление должно отображать информацию для правильной записи библиотеки, что частично сложно из-за перевода. iters между TreeModelFilter и исходным ListStore и т. д. и т. д.

Итак, я спрашиваю, каков рекомендуемый способ написания надежных модульных тестов для такого приложения с графическим интерфейсом? Я видел, что для этого есть несколько библиотек, но основные из них для pygtk не обновлялись годами, поэтому они почти наверняка потерпят неудачу при самоанализе PyGObject. Возможно, я недостаточно изобретателен, чтобы найти хороший способ сделать это с помощью модуля Python unittest, поэтому я открыт для предложений.


person Community    schedule 26.08.2011    source источник
comment
И прежде чем кто-либо спросит: pygtk не поддерживает GTK 3, но я обнаружил, что поддержка интроспекции pygobject в GTK 2 была слишком неполной, чтобы на нее полагаться.   -  person    schedule 26.08.2011
comment
Для меня лучший способ избежать регрессии при использовании графического интерфейса — это выполнять ручные тесты. Unittest действительно хорош для тестирования рабочих функций (например, в случае MVC), но я не знаю, как вы можете справиться с графическим...   -  person ykatchou    schedule 31.08.2011
comment
Это то, чем я занимаюсь, но, видимо, у меня это не очень хорошо получается, так как в каждом выпуске я что-то упускаю.   -  person    schedule 31.08.2011
comment
вы проверили @ unpythonic.blogspot.com/2007/03/unit -testing-pygtk.html?   -  person evandrix    schedule 31.08.2011
comment
Вы должны были поставить это как ответ. Я не сталкивался с таким методом. Я думаю, что с помощью этого метода я мог бы собрать несколько сложных тестовых сценариев.   -  person    schedule 31.08.2011


Ответы (4)


Вы уверены, что хотите выполнить модульное тестирование графического интерфейса? Ваш пример сложности включает более 1 единицы и, следовательно, является интеграционным тестом.

Если вы действительно хотите провести модульное тестирование, вы должны иметь возможность создать экземпляр одного класса, предоставляющего макеты или заглушки для его зависимостей, а затем вызывать методы для него, как это делает инфраструктура графического интерфейса, например. клик пользователя. Это может быть утомительно, и вы должны точно знать, как инфраструктура графического интерфейса отправляет пользовательский ввод в ваши классы.

Мой совет — положить еще больше вещей в модели. Для вашего примера вы можете создать FilterManager, который абстрагирует все фильтры/выборы/отображения за одним методом. Затем выполните модульное тестирование.

person Jürgen Strobel    schedule 31.08.2011
comment
Ах, возможно, тогда я ошибаюсь в терминах (прошло почти 10 лет с тех пор, как я узнал/использовал что-либо из этого). Если я могу наивно спросить, то является ли интеграционное тестирование столь же надежно определенным или проектируемым, как модульное тестирование? Тем не менее, я думаю, что многое из этого можно протестировать так, как я написал, используя метод, упомянутый в комментарии к моему вопросу. - person ; 01.09.2011
comment
Ну, основная концепция модульного тестирования заключается в тестировании одного модуля за раз, чтобы тесты были полными, простыми, быстрыми и имели возможность точно определять сбои. Иногда это сложно, особенно для графических интерфейсов. Возможно, вы сможете использовать некоторые из модулей юнит-тестирования Python и для не-юнит-тестов, но вы также потеряете некоторые преимущества, и я бы больше не называл это юнит-тестированием. - person Jürgen Strobel; 02.09.2011
comment
Это не настоящий ответ ... Очевидно, он хочет провести интеграционное тестирование с PyGTK, поэтому укажите ему правильное направление вместо исправления терминологии. - person schlamar; 30.08.2013
comment
@schlamar Я бы предпочел, чтобы вы дали свой ответ, а не намекали на другой вариант и голосование против. У меня нет опыта интеграционного тестирования. - person Jürgen Strobel; 16.09.2013
comment
Возможно, вам стоит проверить эту ссылку: obeythetestinggoat.com/ - person schlamar; 24.09.2013

Существует отличный способ протестировать функции и виджеты PyGTK напрямую, без прохождения фреймворков приемочного/функционального/интеграционного тестирования, которые, похоже, уходят в небытие. Я узнал об этом из этого поста, который говорит сам за себя. Но основная идея заключается в том, что вы рассматриваете свои виджеты как функции/классы и можете тестировать их напрямую. Если вам нужно обрабатывать обратные вызовы и т. д., есть изящный трюк, который я воспроизведу здесь:

import time
import gtk

# Stolen from Kiwi
def refresh_gui(delay=0):
  while gtk.events_pending():
      gtk.main_iteration_do(block=False)
  time.sleep(delay)

Как упоминалось в сообщении в блоге, этот код — LGPL. В противном случае, если подумать, пока вы не show() не используете окна или виджеты, вы можете тестировать их сколько угодно, и они должны вести себя так, как если бы они были реальными, потому что в некотором смысле они таковы. Они просто не отображаются.

Конечно, вам нужно имитировать взаимодействие с кнопками и интерактивными виджетами самостоятельно, например, вызвав clicked() на кнопке. См. еще раз отличный пост Али Афшара о модульном тестировании в PyGTK.

person anarcat    schedule 18.01.2013

Придерживаясь идеи, что Юрген был прав в том, что меня не интересует модульное тестирование, а интересует интеграционное тестирование, я также нашел этот фреймворк на freedesktop.org: http://ldtp.freedesktop.org/wiki/

Это позволяет автоматизировать различные тесты для приложений с графическим интерфейсом с поддержкой специальных возможностей (включая GTK, Qt, Swing и т. д.).

person Community    schedule 26.02.2012

Вы можете использовать фреймбуфер X11:

Xvfb :119 -screen 0 1024x768x16 &
export DISPLAY=:119
... run your tests

Будьте уверены, чтобы не ввести gtk.main(), так как это будет ждать ввода мыши или клавиатуры. Вы можете использовать этот шаблон, чтобы позволить gtk обрабатывать все события:

def refresh_gui():
  while gtk.events_pending():
      gtk.main_iteration_do(block=False)

Насколько я знаю, вы не можете видеть свое приложение, но вы можете проверить свои обратные вызовы.

person guettli    schedule 05.05.2014
comment
xvfb-run -a testname лучше - person lidaobing; 21.04.2021