raspberry - ¿Cuál es la forma recomendada de probar las aplicaciones de Python GUI?
pyqt (4)
Actualmente soy lo suficientemente tonto como para tratar de mantener dos bases de código paralelas para una aplicación de escritorio Python, una usando la introspección PyGObject para GTK 3 y otra usando PyGTK para GTK 2. Trabajo principalmente en la rama PyGObject y luego transfiero los puertos al Rama PyGTK. Debido a todas las pequeñas diferencias entre estas implementaciones, a menudo pasan por alto las cosas y causan roturas que extraño y lanzo accidentalmente, solo para ser capturado por los usuarios.
Estoy tratando de encontrar una buena forma de diseñar algunas pruebas unitarias que, preferiblemente, serían adecuadas para funcionar en ambas bases de código. No es un programa excesivamente complicado (es esencialmente una herramienta de administración de bibliotecas, imagínese como 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
Intenté separar las vistas de los modelos tanto como sea posible. Cada uno de esos elementos se implementa en su propia clase (bueno, en clases que heredan de las clases GTK enumeradas). Los ListViews se combinan con otras clases que heredan de ListStores. La biblioteca en sí es manejada por una clase diferente. No obstante, hay interacciones entre los widgets que deben probarse. Por ejemplo, si el usuario selecciona un elemento particular en la vista de filtro, filtra la biblioteca y luego selecciona un elemento de los resultados filtrados, la vista de texto debe mostrar la información para la entrada correcta de la biblioteca, que es semi complicada debido a la traducción entre TreeModelFilter y el ListStore original, etc. etc.
Entonces, pregunto, ¿cuál es la forma recomendada para escribir pruebas unitarias robustas para una aplicación GUI? He visto que hay algunas bibliotecas para esto, pero las principales para pygtk no se han actualizado en años, por lo que seguramente fallarán con la introspección de PyGObject. Tal vez no soy lo suficientemente creativo como para descubrir una buena forma de hacerlo utilizando el módulo unittest
de Python, por lo que estoy abierto a sugerencias.
¿Estás seguro de que quieres probar la GUI por unidad ? Su ejemplo de complejidad implica más de 1 unidad y, por lo tanto, es una prueba de integración.
Si realmente quieres probar la unidad, deberías ser capaz de crear una instancia de una sola clase que proporcione simulaciones o stubs para sus dependencias, y luego invocar métodos como el marco de la GUI para, por ejemplo, un clic del usuario. Esto puede ser tedioso y debe saber exactamente cómo el marco de la GUI distribuye la información del usuario a sus clases.
Mi consejo es poner aún más cosas en los modelos. Para su ejemplo dado, podría crear un FilterManager que resuma todo el filtro / seleccionar / mostrar cosas detrás de un único método. Luego prueba la unidad.
Existe una gran manera de probar las funciones y los widgets de PyGTK directamente, sin pasar por marcos de prueba de aceptación / funcional / de integración que caminan hacia el olvido. Aprendí sobre esto en esta publicación que es bastante auto explicativa. Pero la idea básica es que trate sus widgets como funciones / clases, y puede probarlos directamente. Si necesita procesar devoluciones de llamada, etc., hay un buen truco que reproduciré aquí:
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)
Como mencioné en la publicación del blog, este código es LGPL. De lo contrario, cuando lo piense, siempre y cuando no show()
ventanas o widgets, puede probarlos todo lo que quiera y se comporten como si fueran reales porque, de alguna manera, lo son. Simplemente no se muestran.
Por supuesto, necesita simular la interacción en los botones y widgets interactivos usted mismo al hacer clicked()
en un botón presionado (por ejemplo). Ver nuevamente la excelente publicación de Ali Afshar sobre pruebas unitarias en PyGTK .
Puede usar un framebuffer X11:
Xvfb :119 -screen 0 1024x768x16 &
export DISPLAY=:119
... run your tests
Asegúrese de no ingresar gtk.main()
, ya que esto esperaría la entrada del mouse o del teclado. Puede usar este patrón para dejar que gtk maneje todos los eventos:
def refresh_gui():
while gtk.events_pending():
gtk.main_iteration_do(block=False)
AFAIK no puede ver su aplicación, pero puede probar sus devoluciones de llamada.
Siguiendo con el tema que Jürgen tenía razón al decir que no estoy interesado en las pruebas unitarias , pero en realidad estaba interesado en las pruebas de integración, también encontré este marco de freedesktop.org: http://ldtp.freedesktop.org/wiki/
Permite automatizar una variedad de pruebas para aplicaciones de GUI habilitadas para accesibilidad (incluidas GTK, Qt, Swing, etc.).