【问题标题】:Python Tkinter GUI AutomationPython Tkinter GUI 自动化
【发布时间】:2020-10-01 08:47:48
【问题描述】:

我想进入 GUI 自动化,以便在我自己的程序上运行测试。我要测试的程序是用 Python 编写的,并使用 Tkinter 作为 GUI。测试代码虽然不一定要在 python 中,但 CPP 也可以。我做了一些研究,我已经面临一个问题。

根据我的研究,我发现“Windows 应用程序驱动程序”是一种测试 GUI 的免费方法。还有“WinAppDriver UI Recorder”,使用起来很方便。此外,(在我的情况下)“C:\Program Files (x86)\Windows Kits\10\bin\10.0.19041.0\x86”中的“Inspect.exe”程序对于获取有关 GUI 元素的信息很有用。

假设我有一个像这样的小 Python 代码(仅用于测试):

from Tkinter import *
import ttk

class Test():
    def __init__(self):
        self.root = Tk()
        self.root.geometry("250x100")
        self.text = StringVar()
        self.text.set("Original Text")
        self.buttonA = Button(self.root, textvariable=self.text)
        self.buttonA.configure(text="test")

        self.buttonB = Button(self.root,
                                text="Click to change text",
                                command=self.changeText
                              )
        self.buttonA.pack(side=LEFT)
        self.buttonB.pack(side=RIGHT)
        self.root.mainloop()

    def changeText(self):
        self.text.set("Updated Text")

app=Test()

当运行代码并使用Inspect.exe 检查buttonB 时,我得到的名称是“”(空)。有什么方法可以将该名称更改为具有信息性和有用性的名称,例如计算器示例中的“7”按钮的名称为“Seven”。然后像这样在测试器中使用它:

self.driver.find_element_by_name("Seven").click()

应该是这样的:

self.driver.find_element_by_name("buttonB").click()

以我为例。

【问题讨论】:

    标签: python tkinter ui-automation inspector winappdriver


    【解决方案1】:

    您可以将 tkinter 小部件命名为:

    self.buttonA = Button(self.root, textvariable=self.text,name = 'buttonA')
    

    如果WinAppDriver 无法找到以这种方式命名的 tkinter 小部件。您可以修改代码以模仿 UI 自动化框架的方式调用按钮(并“保持”其他 UI 小部件):

    我修改了您的示例以展示如何做到这一点

    from Tkinter import *
    import ttk
    
    def _widgets_by_name(parent,name,widgets):
        if not parent.winfo_children():
            if name == parent.winfo_name() :
                widgets.append(parent)
        else:
            for child in parent.winfo_children():
                _widgets_by_name(child,name,widgets)
                
    def find_widget_by_name(parent,name):
        ''' ui automation function that can find a widget in an application/hierarchy of widgets by its name '''
        widgets = []
        _widgets_by_name(parent,name,widgets)
        if len(widgets) == 0:
            raise Exception(f'no widget named {name} found')
        elif len(widgets) >1:
            raise Exception(f'multiple widget named {name} found')
        return (widgets[0])
    
    
    class Test():
        def __init__(self):
            self.root = Tk()
            self.root.geometry("250x100")
            self.text = StringVar()
            self.text.set("Original Text")
            self.buttonA = Button(self.root, textvariable=self.text,name = 'button-a')
            self.buttonA.configure(text="test")
    
            self.buttonB = Button(self.root,
                                    text="Click to change text",
                                    command=self.changeText,
                                    name = 'button-b'
                                  )
            self.buttonA.pack(side=LEFT)
            self.buttonB.pack(side=RIGHT)
            # self.root.mainloop() do not start the main loop for testing purpose
            # can still be started outside of  __init__ for normal operation 
    
        def changeText(self):
            self.text.set("Updated Text")
        
    app=Test()
    
    # test the app step by step
    # find one of the buttons and invoke it
    find_widget_by_name(app.root,'button-b').invoke()
    app.root.update() # replace the app mainloop: run the UI refresh once.
    
    assert app.text.get() == "Updated Text"
    

    【讨论】:

    • 我尝试了几乎所有我在互联网上可以找到的与命名 tkinter 小部件有关的东西,但对在 WinAppDriver 中识别它们没有帮助。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-22
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 2021-03-04
    相关资源
    最近更新 更多