Тестирование приложения tkinter

Я написал небольшое приложение, используя python 3 и tkinter. Тестирование каждого виджета, даже если их не так много, кажется сложной задачей, поэтому я хотел написать пару автоматических тестов, чтобы упростить процесс. Я прочитал еще один вопрос, который казался относящимся к этой проблеме, но не соответствовал моим потребностям. Прямо сейчас я провожу тестирование очень просто - я вызываю команду для каждого виджета и вручную щелкаю по нему, чтобы проверить, работает ли он. Это действительно немного ускоряет работу, но я постоянно сталкиваюсь с некоторыми проблемами, например, я не могу автоматически закрывать всплывающие окна (например, showinfo) даже с использованием библиотек для имитации щелчков клавиатуры (а именно pynput). Есть ли эффективный подход к тестированию приложений с использованием tkinter?

Вот код, который я использую прямо сейчас:

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

Вы действительно хотите это проверить? Разве вы не доверяете tkinter, чтобы поступить правильно, когда вы звоните в showinfo?

Stop harming Monica 26.08.2018 15:57
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
2
1
2 537
1

Ответы 1

Я мало что знаю о unittest, но я нашел обходной путь, чтобы закрыть всплывающие диалоговые окна, такие как showinfo, во время тестов. Идея состоит в том, чтобы использовать событие клавиатуры для вызова кнопки диалогового окна. Но поскольку приложение ожидает, пока пользователь закроет всплывающее диалоговое окно, нам нужно заранее запланировать событие клавиатуры с помощью after:

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

Полный пример

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('<Key>', 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('<Return>'))
        v.info_button.invoke()

        # quit
        def cancel():
            self.root.event_generate('<Tab>')
            self.root.event_generate('<Return>')

        v.after(100, cancel)
        v.quit_button.invoke()
        self.assertTrue(v.winfo_ismapped())    
        v.after(100, lambda: self.root.event_generate('<Return>'))
        v.quit_button.invoke()
        with self.assertRaises(tkinter.TclError):
            v.winfo_ismapped()


if __name__ == "__main__":
    unittest.main()

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