自动化 tkinter 文件对话以进行功能测试
Automate tkinter file dialogues for functional testing
我有一个 Python tkinter 脚本,我想对其进行 运行 一些功能测试。该脚本包括 tkinter.filedialog.askopenfilename()
和 tkinter.filedialog.asksaveasfilename()
,所以我想要测试的一部分 uploads/downloads 一个文件。我尝试使用 pyautogui
来尝试自动执行鼠标点击并发送按键以尝试自动执行这些操作,但这样做没有用(屏幕上没有任何可见的变化,也没有加载文件)。
使用 pyautogui 的功能测试尝试
class TestOrganizeAttendance(unittest.TestCase):
def setUp(self):
self.organizer = AttendanceOrganizer()
...
def test_attendance_organizer_window_operation(self):
...
#User clicks button and their computer's files appear
self.organizer.upload_file_button.invoke()
self.assertIn(
"explorer.exe", [p.name() for p in psutil.process_iter()])
#User selects a file to be uploaded
filepath = os.path.abspath(
os.path.join('.', 'tests', 'sample_attendance.csv'))
pyautogui.PAUSE = 2.5
pyautogui.hotkey('alt', 'd')
pyautogui.typewrite(filepath)
pyautogui.hotkey('enter')
....
脚本
class AttendanceOrganizer:
def __init__(self):
self.upload_file_button = tkinter.Button(
self.root, text="Upload File", command=self.upload_file)
self.download_file_button = tkinter.Button(
self.root, text="Download File", command=self.download_file)
...
def upload_file(self):
self.details_var.set(
value="Select a file to upload")
filetypes = [('Comma Separated Values', '.csv')]
filepath = tkinter.filedialog.askopenfilename(
parent=self.root, filetypes=filetypes)
if not (filepath and os.path.splitext(filepath)[-1] == '.csv'):
return
self.upload_var.set(value=filepath)
self.details_var.set(
value=f"File Uploaded\t{self.details_var.get()}")
with open(filepath, encoding='utf-16') as file:
self.values = list(csv.reader(file, delimiter='\t'))
del self.values[0]
self.organize_data_button.config(state='normal')
def download_file(self):
filetypes = [('Comma Separated Values', '.csv')]
filepath = tkinter.filedialog.asksaveasfilename(
parent=self.root, filetypes=filetypes)
with open(f"{filepath}.csv", 'w', newline='') as file:
fieldnames = ["Last", "First", "Joined", "Left"]
writer = csv.DictWriter(
file, fieldnames=fieldnames, delimiter='\t')
writer.writeheader()
for item in self.data:
writer.writerow(self.data[item])
...
上述代码在functional_tests.py
中的问题在于tkinter.filedialog.askopenfilename
和tkinter.filedialog.asksaveaskfilename
都是阻塞函数,即函数必须在进一步代码执行之前完成。避免此问题的最简单方法是使用 threading
创建一个线程,该线程执行与主线程分开的所有 pyautogui
函数。
functional_tests.py 与 pyautogui
class TestOrganizeAttendance(unittest.TestCase):
def setUp(self):
...
def tearDown(self):
...
def automate_file_dialogue(self, filepath):
while "explorer.exe" not in [p.name() for p in psutil.process_iter()]: #Wait for the file dialogue to open
continue
directory, filename = os.path.split(filepath)
pyautogui.hotkey('alt', 'd') #Keyboard shortcut to focus the address bar
pyautogui.typewrite(directory)
pyautogui.hotkey('enter')
pyautogui.hotkey('tab')
pyautogui.hotkey('tab')
pyautogui.hotkey('tab') #Repeatedly press TAB to remove focus from the address bar
pyautogui.hotkey('alt', 'n') #Keyboard shortcut to focus the file name
pyautogui.hotkey(filename)
pyautogui.hotkey('enter')
def test_attendance_organizer_window_operation(self):
...
filepath = os.path.abspath(
os.path.join('tests', 'sample_attendance.csv'))
upload_thread = threading.Thread(
target=self.automate_file_dialogue, args=(filepath,))
upload_thread.start()
upload_thread.start()
self.assertTrue(os.path.exists(filepath))
self.organizer.upload_file_button.invoke()
self.assertIn(
"explorer.exe", [p.name() for p in psutil.process_iter()])
upload_thread.join()
...
filepath = os.path.abspath(
os.path.join('tests', 'new_sample_attendance'))
download_thread = threading.Thread(
target=self.automate_file_dialogue, args=(filepath,))
download_thread.start()
self.assertFalse(os.path.exists(filepath))
self.organizer.download_file_button.invoke()
self.assertIn(
"explorer.exe", [p.name() for p in psutil.process_iter()])
download_thread.join()
我有一个 Python tkinter 脚本,我想对其进行 运行 一些功能测试。该脚本包括 tkinter.filedialog.askopenfilename()
和 tkinter.filedialog.asksaveasfilename()
,所以我想要测试的一部分 uploads/downloads 一个文件。我尝试使用 pyautogui
来尝试自动执行鼠标点击并发送按键以尝试自动执行这些操作,但这样做没有用(屏幕上没有任何可见的变化,也没有加载文件)。
使用 pyautogui 的功能测试尝试
class TestOrganizeAttendance(unittest.TestCase):
def setUp(self):
self.organizer = AttendanceOrganizer()
...
def test_attendance_organizer_window_operation(self):
...
#User clicks button and their computer's files appear
self.organizer.upload_file_button.invoke()
self.assertIn(
"explorer.exe", [p.name() for p in psutil.process_iter()])
#User selects a file to be uploaded
filepath = os.path.abspath(
os.path.join('.', 'tests', 'sample_attendance.csv'))
pyautogui.PAUSE = 2.5
pyautogui.hotkey('alt', 'd')
pyautogui.typewrite(filepath)
pyautogui.hotkey('enter')
....
脚本
class AttendanceOrganizer:
def __init__(self):
self.upload_file_button = tkinter.Button(
self.root, text="Upload File", command=self.upload_file)
self.download_file_button = tkinter.Button(
self.root, text="Download File", command=self.download_file)
...
def upload_file(self):
self.details_var.set(
value="Select a file to upload")
filetypes = [('Comma Separated Values', '.csv')]
filepath = tkinter.filedialog.askopenfilename(
parent=self.root, filetypes=filetypes)
if not (filepath and os.path.splitext(filepath)[-1] == '.csv'):
return
self.upload_var.set(value=filepath)
self.details_var.set(
value=f"File Uploaded\t{self.details_var.get()}")
with open(filepath, encoding='utf-16') as file:
self.values = list(csv.reader(file, delimiter='\t'))
del self.values[0]
self.organize_data_button.config(state='normal')
def download_file(self):
filetypes = [('Comma Separated Values', '.csv')]
filepath = tkinter.filedialog.asksaveasfilename(
parent=self.root, filetypes=filetypes)
with open(f"{filepath}.csv", 'w', newline='') as file:
fieldnames = ["Last", "First", "Joined", "Left"]
writer = csv.DictWriter(
file, fieldnames=fieldnames, delimiter='\t')
writer.writeheader()
for item in self.data:
writer.writerow(self.data[item])
...
上述代码在functional_tests.py
中的问题在于tkinter.filedialog.askopenfilename
和tkinter.filedialog.asksaveaskfilename
都是阻塞函数,即函数必须在进一步代码执行之前完成。避免此问题的最简单方法是使用 threading
创建一个线程,该线程执行与主线程分开的所有 pyautogui
函数。
functional_tests.py 与 pyautogui
class TestOrganizeAttendance(unittest.TestCase):
def setUp(self):
...
def tearDown(self):
...
def automate_file_dialogue(self, filepath):
while "explorer.exe" not in [p.name() for p in psutil.process_iter()]: #Wait for the file dialogue to open
continue
directory, filename = os.path.split(filepath)
pyautogui.hotkey('alt', 'd') #Keyboard shortcut to focus the address bar
pyautogui.typewrite(directory)
pyautogui.hotkey('enter')
pyautogui.hotkey('tab')
pyautogui.hotkey('tab')
pyautogui.hotkey('tab') #Repeatedly press TAB to remove focus from the address bar
pyautogui.hotkey('alt', 'n') #Keyboard shortcut to focus the file name
pyautogui.hotkey(filename)
pyautogui.hotkey('enter')
def test_attendance_organizer_window_operation(self):
...
filepath = os.path.abspath(
os.path.join('tests', 'sample_attendance.csv'))
upload_thread = threading.Thread(
target=self.automate_file_dialogue, args=(filepath,))
upload_thread.start()
upload_thread.start()
self.assertTrue(os.path.exists(filepath))
self.organizer.upload_file_button.invoke()
self.assertIn(
"explorer.exe", [p.name() for p in psutil.process_iter()])
upload_thread.join()
...
filepath = os.path.abspath(
os.path.join('tests', 'new_sample_attendance'))
download_thread = threading.Thread(
target=self.automate_file_dialogue, args=(filepath,))
download_thread.start()
self.assertFalse(os.path.exists(filepath))
self.organizer.download_file_button.invoke()
self.assertIn(
"explorer.exe", [p.name() for p in psutil.process_iter()])
download_thread.join()