Каков рекомендуемый способ unittest приложений Python GUI?

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

Я пытаюсь найдите хороший способ разработать некоторые unittests, которые предпочтительно подходят для работы на обеих кодовых базах. Это не слишком сложная программа (это, по сути, инструмент управления библиотекой, представьте себе, как 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. Сама библиотека обрабатывается другим классом. Тем не менее, есть взаимодействия между виджетами, которые необходимо протестировать. Например, если пользователь выбирает определенный элемент в представлении фильтра, фильтруя библиотеку, а затем выбирает элемент из отфильтрованных результатов, текстовое представление должно отображать информацию для правильной записи библиотеки, которая является полусложной из-за перевода итеров между TreeModelFilter и исходным ListStore и т. д.

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

4 ответов


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

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

мой совет-поместить еще больше вещей в модели. Для вашего примера вы можете создать FilterManager, который абстрагирует все материалы filter/select/display за одним методом. Затем юнит-тест.


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

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() windows или виджеты, вы можете проверить их все, что хотите, и они должны вести себя так, как если бы они были реальными, потому что, в некотором смысле, они есть. Они просто не отображаются.

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


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

Он позволяет автоматизировать различные тесты для приложений GUI с поддержкой доступности (включая GTK, Qt, Swing и т. д.).


вы можете использовать фреймбуфер 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)

AFAIK вы не можете увидеть свое приложение, но вы можете проверить свои обратные вызовы.