Python Unittest Tkinter文件对话框 问题:

Python Unittest Tkinter文件对话框 问题:,python,unit-testing,user-interface,tkinter,Python,Unit Testing,User Interface,Tkinter,有没有办法自动执行tkFileDialog选择以通过unittest运行它?以下是我的应用程序中唯一使用的tkinter: root = Tkinter.Tk() types = [('Comma Separated Values', '.csv'), ('All Files', '*')] filename = tkFileDialog.askopenfilename(parent=root, filetypes=

有没有办法自动执行
tkFileDialog
选择以通过
unittest
运行它?以下是我的应用程序中唯一使用的
tkinter

root = Tkinter.Tk()
types = [('Comma Separated Values', '.csv'), ('All Files', '*')]
filename = tkFileDialog.askopenfilename(parent=root,
                                        filetypes=types)
root.destroy()
编辑:我没有提到这部分代码被困在我无法控制的类的方法调用中。

背景 我构建了一个本地应用程序,它在
localhost
上创建了一个http服务器,并在web浏览器中使用HTML/CSS/JS运行其GUI。由于浏览器的限制,我无法使用内置的文件对话框,因此必须通过Python发送此请求。我想让它在带有内置Python 2.5的OSX上运行。我不太熟悉
Tcl/Tk

尝试#1 如果我可以访问底层的小部件,我可以像中一样生成点击。但是,在我看来,第48-50行中的
Tcl
调用被阻塞了。这是正确的假设吗

尝试#2 我想可能有一种方法可以通过
root.tk.call
直接使用
Tcl
命令。由于我使用的是
Python2
,我认为底层的
Tcl
是对
tk\u getOpenFile
的一次调用。我是否必须确保
Tcl
解释器是线程化的?这里有什么
Tcl/Tk
命令可以帮助我吗

尝试#3 我可以使用
os.listdir
等从头开始实现文件选择(可能在单独的HTML页面中与服务器来回通信)。这将不仅仅是一点痛苦,而且有望避免


解决方案 根据A.Rodas下面的回答,我得出以下结论:

import tkFileDialog
old_dialog = tkFileDialog.askopenfilename
try:
    tkFileDialog.askopenfilename = lambda *args, **kw: filename

    # First test dialog cancelled
    filename = ''
    method_that_calls_tk()
    # run some assertions

    # Next test a valid file name with valid contents
    filename = self.VALID_FILENAME
    method_that_calls_tk()
    # run some assertions

    # Now test a valid file name with invalid contents
    filename = self.INVALID_CONTENTS_FILENAME
    method_that_calls_tk()
    # run some assertions

    # Now test an invalid file name
    filename = self.INVALID_FILENAME
    method_that_calls_tk()
    # run some assertions
finally:
    tkFileDialog.askopenfilename = old_dialog

Tkinter代码的单元测试不是一个容易的问题。例如,没有适当的测试套件,即使它是标准库的一部分。既然您提到这将是Tkinter在应用程序中的唯一用途,我建议对这段代码的结果进行单元测试:
filename
的值

例如,您可以对.csv文件进行测试,对不正确的文件扩展名进行测试。由于
tkFileDialog
在用户关闭时返回空字符串,因此还添加了一个测试,其中
filename='


您只需将呼叫打到tkinter: 修补tk.tk(),因为大多数CI都会出错,因为它们没有显示。 还要修补“文件”对话框,以便您可以模拟返回值,并按照预期调用它

@patch('your_module.tk.Tk')
def test_your_stuff(self, Tk)

    with @patch('your_module.tkFileDialog.askopenfilename') as file_dialog:
        expected = 'expected return value'
        assert expected = your_function_calling_file_dialog()

        file_dialog.assert_called_once_with(whatever, you, expect, it, to, be, called, with)

这帮助我想出了一个更简单、更有效的解决方案。我把它作为我问题的编辑,以防有人无意中发现。谢谢这是在哪个站台?在X11上注入事件在某种程度上是可能的,但对于其他平台(即使用真正的本机对话框的平台),这非常困难。更简单的方法是完全模拟
tkFileDialog
…这将在X11上进行。我最终模拟了
askopenfile
函数。出于好奇,您是否有链接或资源,我可以从中了解X11上的注入事件?
@patch('your_module.tk.Tk')
def test_your_stuff(self, Tk)

    with @patch('your_module.tkFileDialog.askopenfilename') as file_dialog:
        expected = 'expected return value'
        assert expected = your_function_calling_file_dialog()

        file_dialog.assert_called_once_with(whatever, you, expect, it, to, be, called, with)