Probando la aplicación tkinter

Escribí una pequeña aplicación usando python 3 y tkinter. Probar todos los widgets, a pesar de que no hay muchos de ellos, se siente desalentador, así que quería escribir un par de pruebas automatizadas para simplificar el proceso. Leí alguna otra pregunta que parecía relevante para este problema, pero ninguna se ajustaba a mis necesidades. Ahora mismo estoy haciendo las pruebas de una manera muy simple: invoco el comando para cada widget y hago clic manualmente en él para ver si funciona. Hace las cosas un poco más rápido, pero constantemente me encuentro con algunos problemas, es decir, no puedo cerrar automáticamente las ventanas emergentes (como showinfo), incluso con el uso de bibliotecas para simular los clics del teclado (es decir, pynput). ¿Existe un enfoque eficiente para probar aplicaciones usando tkinter?

Aquí está el código que uso ahora:

import tkinter as tkinter import unittest from mygui import MyGUI class TKinterTestCase(unittest.TestCase): def setUp(self): self.root = tkinter.Tk() def tearDown(self): if self.root: self.root.destroy() def test_enter(self): v = MyGUI(self.root) v.info_button.invoke() v.close_button.invoke() v.btnOut.invoke() if __name__ == "__main__": unittest.main() 

No sé mucho acerca de unittest pero encontré una solución para cerrar diálogos emergentes como showinfo durante las pruebas. La idea es usar el evento de teclado para invocar el botón del diálogo. Pero como la aplicación está esperando a que el usuario cierre el cuadro de diálogo emergente, debemos progtwigr por adelantado el evento de teclado usando after :

 self.root.after(100, self.root.event_generate('')) v.button.invoke() 

Ejemplo completo

 import tkinter from tkinter import messagebox import unittest class MyGUI(tkinter.Frame): def __init__(self, master, **kw): tkinter.Frame.__init__(self, master, **kw) self.info_button = tkinter.Button(self, command=self.info_cmd, text='Info') self.info_button.pack() self.quit_button = tkinter.Button(self, command=self.quit_cmd, text='Quit') self.quit_button.pack() def info_cmd(self): messagebox.showinfo('Info', master=self) def quit_cmd(self): confirm = messagebox.askokcancel('Quit?', master=self) if confirm: self.destroy() class TKinterTestCase(unittest.TestCase): def setUp(self): self.root = tkinter.Tk() self.root.bind('', lambda e: print(self.root, e.keysym)) def tearDown(self): if self.root: self.root.destroy() def test_enter(self): v = MyGUI(self.root) v.pack() self.root.update_idletasks() # info v.after(100, lambda: self.root.event_generate('')) v.info_button.invoke() # quit def cancel(): self.root.event_generate('') self.root.event_generate('') v.after(100, cancel) v.quit_button.invoke() self.assertTrue(v.winfo_ismapped()) v.after(100, lambda: self.root.event_generate('')) v.quit_button.invoke() with self.assertRaises(tkinter.TclError): v.winfo_ismapped() if __name__ == "__main__": unittest.main()