You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

pytest测试Tkinter待办清单程序时代码无法运行问题求助

问题根因

你的pytest流程无法正常执行是三个核心问题叠加导致的,和pytest框架本身无关:

  • 模块导入直接触发Tk主循环:你的to_do_list.py末尾直接写了window.mainloop(),没有做运行入口保护。只要测试代码执行from to_do_list import add_item, delete_item,就会直接启动Tkinter窗口阻塞整个测试流程,不手动关闭窗口pytest根本不会往下执行测试用例。
  • 测试用例传参完全不匹配函数签名:业务代码里add_item需要接收Entry组件实例、Listbox组件实例两个参数,你测试里只传了一个字符串;delete_item需要接收Listbox组件实例,你测试里调用时没有传任何参数,就算主循环不卡,跑起来也会直接报参数缺失的TypeError。
  • 断言逻辑完全不匹配函数行为:两个业务函数都没有写return返回值,默认返回None,你写的assert add_item('test') == 'test'从逻辑上就不可能成立。
修复步骤
  1. 先给主程序加运行入口保护
    把主程序末尾的窗口启动代码放到if __name__ == "__main__":块里,只有直接运行这个脚本的时候才启动GUI,被测试文件等其他模块导入的时候不会触发主循环:
if __name__ == "__main__":
    window.update()
    window.mainloop()

额外提醒:你的业务代码里用到了END、ACTIVE这两个Tkinter常量,记得在to_do_list.py顶部补上from tkinter import END, ACTIVE,不然调用函数时会报常量未定义的错。

  1. 重写测试用例,正确初始化Tk测试组件
    Tkinter的所有控件都必须依附于一个存在的Tk根窗口,测试里要先创建根窗口、测试用的Entry和Listbox控件,再传参给业务函数;断言不要判断不存在的返回值,要判断实际的操作结果:比如Listbox里的条目有没有正确增减、文件有没有正确写入。
    参考测试代码如下,用pytest自带的tmp_path fixture处理文件写入,避免污染你本地真实的items.txt:
from tkinter import Tk, Entry, Listbox
import pytest
from to_do_list import add_item, delete_item

@pytest.fixture
def tk_components(monkeypatch, tmp_path):
    # 初始化Tk根窗口和测试控件
    root = Tk()
    entry = Entry(root)
    listbox = Listbox(root)
    # 把业务代码里写入的items.txt重定向到临时目录,不影响本地文件
    test_file = tmp_path / "items.txt"
    def patched_open(file, mode, *args, **kwargs):
        if file == "items.txt":
            return open(test_file, mode, *args, **kwargs)
        return open(file, mode, *args, **kwargs)
    monkeypatch.setattr("builtins.open", patched_open)
    yield entry, listbox, test_file
    # 测试结束销毁根窗口
    root.destroy()

def test_add_item(tk_components):
    entry, listbox, test_file = tk_components
    # 给输入框插入测试内容
    entry.insert(0, "测试待办项")
    # 调用添加函数
    add_item(entry, listbox)
    # 断言列表里确实插入了内容
    assert listbox.get(0) == "测试待办项"
    # 断言文件确实写入了内容
    assert "测试待办项" in test_file.read_text(encoding="utf-8")

def test_delete_item(tk_components):
    entry, listbox, test_file = tk_components
    # 先插入一个测试项并选中
    entry.insert(0, "待删除项")
    add_item(entry, listbox)
    listbox.select_set(0)
    # 调用删除函数
    delete_item(listbox)
    # 断言列表里已经没有该项
    assert listbox.size() == 0
  1. 修复业务代码里的逻辑bug
    你现在的delete_item函数本身有逻辑问题,就算测试写对了也跑不通:
  • 以r+模式打开文件直接写入会把新内容追加到旧内容后面,不会覆盖原有内容,会导致文件内容重复
  • 遍历列表的同时执行remove操作会漏遍历元素
  • 用line[:-2]做匹配很容易切掉正常的条目内容,判断逻辑不可靠
    建议重写文件操作部分,先读全量内容,过滤掉要删除的条目之后再用w模式覆盖写回文件。

内容的提问来源于stack exchange,提问作者Izy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.03 01:30:46