Python 3.x 为什么不可能在代码的单元测试中获取Tk`StringVar`,而该代码在设置和获取`StringVar`方面没有问题?

Python 3.x 为什么不可能在代码的单元测试中获取Tk`StringVar`,而该代码在设置和获取`StringVar`方面没有问题?,python-3.x,tkinter,tk,ttk,Python 3.x,Tkinter,Tk,Ttk,我想编写一个需要读取tkinterStringVar的单元测试。我没走多远。单元测试如下所示: def test_show_headers(self): cell = common.winfo_path(self.FIRST_CELL, self.table) print(cell) # cell.setvar(cell['textvariable'], 'hello mum') print(cell.getvar(cell['textvariable']))

我想编写一个需要读取tkinter
StringVar
的单元测试。我没走多远。单元测试如下所示:

def test_show_headers(self):
    cell = common.winfo_path(self.FIRST_CELL, self.table)
    print(cell)
    # cell.setvar(cell['textvariable'], 'hello mum')
    print(cell.getvar(cell['textvariable']))
.table outer frame.scrolled canvas.table frame.r0c0

Error
Traceback (most recent call last):
  File "E:\Stephenff\Programming\Study\Scratch\test_table_display.py", line 249, in test_show_headers
    print(cell.getvar(cell['textvariable']))
  File "D:\Python34\lib\tkinter\__init__.py", line 502, in getvar
    return self.tk.getvar(name)
_tkinter.TclError: can't read "PY_VAR0": no such variable
def _make_cell(self, parent, row_id, column_ix, cell_text):

    tk_string = tk.StringVar()
    cell = ttk.Entry(parent, name=self.cell_name(row_id, column_ix),
                     textvariable=tk_string)
    cell.setvar(cell['textvariable'], cell_text)
    cell.grid(row=row_id, column=column_ix)
    cell.bind('<Return>',
              (lambda event: self._cell_callback(
                  event, self.CellClicked(row_id, self.headers[column_ix]),
                  cell.getvar(cell['textvariable']))))

def _cell_callback(self, event=None, location=None, text=None):
    self.cell_clicked = location
    self.cell_text = text
    self.parent.focus_set()
    self.destroy()
输出如下所示:

def test_show_headers(self):
    cell = common.winfo_path(self.FIRST_CELL, self.table)
    print(cell)
    # cell.setvar(cell['textvariable'], 'hello mum')
    print(cell.getvar(cell['textvariable']))
.table outer frame.scrolled canvas.table frame.r0c0

Error
Traceback (most recent call last):
  File "E:\Stephenff\Programming\Study\Scratch\test_table_display.py", line 249, in test_show_headers
    print(cell.getvar(cell['textvariable']))
  File "D:\Python34\lib\tkinter\__init__.py", line 502, in getvar
    return self.tk.getvar(name)
_tkinter.TclError: can't read "PY_VAR0": no such variable
def _make_cell(self, parent, row_id, column_ix, cell_text):

    tk_string = tk.StringVar()
    cell = ttk.Entry(parent, name=self.cell_name(row_id, column_ix),
                     textvariable=tk_string)
    cell.setvar(cell['textvariable'], cell_text)
    cell.grid(row=row_id, column=column_ix)
    cell.bind('<Return>',
              (lambda event: self._cell_callback(
                  event, self.CellClicked(row_id, self.headers[column_ix]),
                  cell.getvar(cell['textvariable']))))

def _cell_callback(self, event=None, location=None, text=None):
    self.cell_clicked = location
    self.cell_text = text
    self.parent.focus_set()
    self.destroy()
第一个print语句确认我有正确的tkinter小部件
(.table….r0c0)
,错误显示小部件有正确的
StringVar
标识符
“PY_VAR0”
,尽管它没有标识任何内容

如果我取消注释
setvar
行,输出将更改为:

.table outer frame.scrolled canvas.table frame.r0c0
hello mum
显然,
“PY\u VAR0”
标识的值丢失了。让我困惑的是,
getvar
在测试代码中成功地用于创建回调。该代码的简化版本如下所示:

def test_show_headers(self):
    cell = common.winfo_path(self.FIRST_CELL, self.table)
    print(cell)
    # cell.setvar(cell['textvariable'], 'hello mum')
    print(cell.getvar(cell['textvariable']))
.table outer frame.scrolled canvas.table frame.r0c0

Error
Traceback (most recent call last):
  File "E:\Stephenff\Programming\Study\Scratch\test_table_display.py", line 249, in test_show_headers
    print(cell.getvar(cell['textvariable']))
  File "D:\Python34\lib\tkinter\__init__.py", line 502, in getvar
    return self.tk.getvar(name)
_tkinter.TclError: can't read "PY_VAR0": no such variable
def _make_cell(self, parent, row_id, column_ix, cell_text):

    tk_string = tk.StringVar()
    cell = ttk.Entry(parent, name=self.cell_name(row_id, column_ix),
                     textvariable=tk_string)
    cell.setvar(cell['textvariable'], cell_text)
    cell.grid(row=row_id, column=column_ix)
    cell.bind('<Return>',
              (lambda event: self._cell_callback(
                  event, self.CellClicked(row_id, self.headers[column_ix]),
                  cell.getvar(cell['textvariable']))))

def _cell_callback(self, event=None, location=None, text=None):
    self.cell_clicked = location
    self.cell_text = text
    self.parent.focus_set()
    self.destroy()
致:

之后,unittest
test\u show\u headers
会生成以下各项的正确输出:

.table outer frame.scrolled canvas.table frame.r0c0
Date
然而,重构不应该能够产生这种变化。这是怎么可能的?为什么原始代码会导致Tk的
StringVar
丢失

更新2

此程序中的任何位置都不使用线程

我正在测试的类是ttk.Frame的一个子类,它依赖于外部提供的根窗口。对于测试,根窗口由unittest
setUp
方法提供,并在
tearDown
方法中删除

def setUp(self, withdraw=True):
    self.parent = tk.Tk()
    if withdraw:
        self.parent.withdraw()

def tearDown(self):
    self.parent.update()
    self.parent.destroy()

共有三个测试夹具,它们是从包含
设置
拆卸
的公共基础子类划分的。我已经确认这三个函数实际上都调用了
tearDown
。据我所知,通过阅读代码,tcl/tk解释器只有一个实例在运行

单元测试是否可能在单独的线程中运行,或者有自己的根窗口(读:它有自己的内部tcl/tk解释器)?我已经研究了您的有用建议,并在我的原始问题中添加了一些额外的信息。如果我知道一种计算活动tcl/tk解释器实际数量的方法,我会对此感到更舒服。你知道有没有可能吗?(想想看,这将是一个在每次tkinter测试中防止副作用的有价值的工具)我不知道该怎么做,尽管回答这个问题的简单方法是问“你实例化了多少次
Tk
类?”。每次你这样做,你都会得到一个新的口译员。如果您创建了一个小部件而没有首先创建根窗口,则会为您创建一个根窗口(和解释器)。如果您这样做,然后创建自己的根窗口,您现在有两个。我已经重构了测试代码,删除了除一个之外的所有测试。它实例化Tk一次,并将其销毁。被测代码完全由unittest控制。它不包含
Tk
的任何实例化。widget是在那里创建的,但只能在unittest的
Tk
实例中。如果问题出在
Tk
的第二个实例上,我在“更新1”中描述的重构将产生更改创建
StringVar
Tk
实例的效果。换句话说,在重构在正确的实例中创建StringVar之前,StringVar是在错误的实例中创建的。单元测试是否可能在单独的线程中运行,或者有自己的根窗口(读取:它自己的内部tcl/tk解释器)?我已经调查了你的有益建议,并在我原来的问题中添加了一些额外的信息。如果我知道一种计算活动tcl/tk解释器实际数量的方法,我会对此感到更舒服。你知道有没有可能吗?(想想看,这将是一个在每次tkinter测试中防止副作用的有价值的工具)我不知道该怎么做,尽管回答这个问题的简单方法是问“你实例化了多少次
Tk
类?”。每次你这样做,你都会得到一个新的口译员。如果您创建了一个小部件而没有首先创建根窗口,则会为您创建一个根窗口(和解释器)。如果您这样做,然后创建自己的根窗口,您现在有两个。我已经重构了测试代码,删除了除一个之外的所有测试。它实例化Tk一次,并将其销毁。被测代码完全由unittest控制。它不包含
Tk
的任何实例化。widget是在那里创建的,但只能在unittest的
Tk
实例中。如果问题出在
Tk
的第二个实例上,我在“更新1”中描述的重构将产生更改创建
StringVar
Tk
实例的效果。换句话说,在重构在正确的实例中创建StringVar之前,StringVar是在错误的实例中创建的。单元测试是否可能在单独的线程中运行,或者有自己的根窗口(读取:它自己的内部tcl/tk解释器)?我已经调查了你的有益建议,并在我原来的问题中添加了一些额外的信息。如果我知道一种计算活动tcl/tk解释器实际数量的方法,我会对此感到更舒服。你知道有没有可能吗?(想想看,这将是一个在每次tkinter测试中防止副作用的有价值的工具)我不知道该怎么做,尽管回答这个问题的简单方法是问“你实例化了多少次
Tk
类?”。每次你这样做,你都会得到一个新的口译员。如果您创建了一个小部件而没有首先创建根窗口,则会为您创建一个根窗口(和解释器)。如果您这样做,然后创建自己的根窗口,您现在有两个。我已经重构了测试代码,删除了除一个之外的所有测试。它实例化Tk一次,并将其销毁。被测代码完全由unittest控制。它不起作用