【问题标题】:Unittest for invoking a TKinter GUI用于调用 TKinter GUI 的单元测试
【发布时间】:2019-05-07 13:01:19
【问题描述】:

假设一个脚本启动 TKinter GUI(例如,scripts/launch_GUI.py)并且是 PyPI 包的一部分(例如,MyPackage)。

.
├── appveyor.yml
├── MyPackage
│   ├── TkOps.py
│   └── CoreFunctions.py
├── README.md
├── requirements.txt
├── scripts
│   ├── launch_CLI.py
│   └── launch_GUI.py
├── setup.py
└── tests
    └── MyPackage_test.py

启动脚本非常简约:

#!/usr/bin/env python2
if __name__ == '__main__':
    import sys, os
    sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'MyPackage'))
    import TkOps
    TkOps.start_GUI()

如果 TKinter GUI 在启动 launch_GUI.py 时正确启动,您会建议评估什么 unittest

注意:我只想评估启动脚本是否正常工作并启动 GUI,而不是用户是否可以与 GUI 交互。

【问题讨论】:

  • 不能查看窗口的state()吗?
  • @TeeKea 你能进一步解释一下吗?我不知道函数 state 并且似乎找不到关于它的任何信息:>>> import tkinter >>> help("state") no Python documentation found for 'state'
  • 请看下面的链接。我想您可以检查state() 是否为'normal。你能展示一些你用来创建顶级窗口的代码吗? effbot.org/tkinterbook/wm.htm#Tkinter.Wm.state-method
  • 你的 start_GUI() 函数是做什么的?它会创建一个对象吗?如果是这样:为什么不测试对象的类型,如果它是 那么你知道它至少启动了一个 tk 窗口。例如,在 python 解释器窗口中输入以下命令将输出上述结果:“import tkinter as tk; root=tk.Tk(); type(root)”
  • 上面的评论变得越来越庞大:在建议的命令中,我隐式地将根对象创建为 tkinter 窗口,然后调用 type() 来确认我的根对象的类型。如果您的函数创建一个 tkinter 窗口作为对象,您应该能够检查它的类型,确认它已创建。

标签: python python-2.7 unit-testing user-interface tkinter


【解决方案1】:

可以说您需要功能测试而不是单元测试,但我们还是试试吧!

虽然可以通过exec() 测试启动脚本,但这被认为是不好的做法。让我们重构它:

def main():
    import sys, os
    sys.path.append(os.path.join(os.path.dirname(__file__), '..', 'MyPackage'))
    import TkOps
    TkOps.start_GUI()

if __name__ == '__main__':
    main()

那我们来确定一下单元测试应该测试什么,例如:

  • sys.path 更新为 MyPackage 的正确路径
  • start_GUI 被调用

那么 mokist [1] 单元测试可能如下所示:

@mock.patch("sys.path", copy.copy(sys.path))
@mock.patch.dict(sys.modules, TkOps=mock.MagicMock())
def test_main():
    main()
    # minimal validation of sys.path side effect
    # ideally this would check that path bit points to real directory
    assert any(p.endswith("/MyPackage") for p in sys.path)
    # validation of expected call
    assert sys.modules["TkOps"].start_GUI.called

经典单元测试需要在 GUI 中设置一个逃生舱口,例如:

def start_GUI(dry_run=False):
    import tk
    ...
    if not dry_run: tk.foobar()

[1]https://agilewarrior.wordpress.com/2015/04/18/classical-vs-mockist-testing/

【讨论】:

  • 感谢您提供这个复杂的答案。我需要一些时间来理解这一切。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-05
  • 2020-10-01
  • 2012-03-06
  • 2018-08-06
  • 2023-03-27
相关资源
最近更新 更多