8

Question

Is there any way to automate a tkFileDialog selection to run it through unittest? The following is the only use of tkinter in my application:

root = Tkinter.Tk()
types = [('Comma Separated Values', '.csv'), ('All Files', '*')]
filename = tkFileDialog.askopenfilename(parent=root,
                                        filetypes=types)
root.destroy()

Edit: I didn't mention that this part of the code was trapped in a method call from a class outside my control.


Background

I've built a local app that creates an http server on localhost and runs its GUI with HTML/CSS/JS in a web browser. Because of browser restrictions, I can't use the built-in file dialog and so have to send this request through Python. I want this to run on a OSX with the built-in Python 2.5. I'm not very familiar with Tcl/Tk.

Attempt #1

If I could get to the underlying widgets, I could generate the clicks like in this question. However, looking at the dialog source, it appears to me that the Tcl call in lines 48-50 is blocking. Is this a correct assumption?

Attempt #2

I thought there might be a way using Tcl commands directly through root.tk.call. Since I'm on Python2, I think the underlying Tcl is a single call to tk_getOpenFile. Would I have to ensure the Tcl interpreter is threaded? Is there any Tcl/Tk command that can help me out here?

Attempt #3

I could implement the file selection from scratch using os.listdir etc. (Probably in a separate HTML page communicating back and forth with the server). It would be more than a little painful and hopefully avoidable.


Solution

Based on A. Rodas's answer below, I came up with the following:

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
4

2 回答 2

4

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

例如,您可以对 .csv 文件进行测试,对不正确的文件扩展名进行另一次测试。由于tkFileDialog如果用户关闭它会返回一个空字符串,因此还要添加一个测试 where filename = ''

import unittest

class TestFileDialog(unittest.TestCase):

    def test_dialog_closed(self):
        filename = ''
        # ...

    def test_incorrect_extension(self):
        filename = '/path/to/another/filetype'
        # ...

    def test_csv_extension(self):
        filename = '/path/to/correct/file.csv'
        # ...
于 2013-06-15T11:49:08.487 回答
1

您可以只修补对 tkinter 的调用:patch 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)
于 2019-01-28T22:11:11.583 回答