如何对 GUI 进行单元测试?

Posted

技术标签:

【中文标题】如何对 GUI 进行单元测试?【英文标题】:How can I unit test a GUI? 【发布时间】:2010-09-17 22:40:44 【问题描述】:

我的代码中的计算经过了很好的测试,但由于 GUI 代码太多,我的整体代码覆盖率低于我的预期。是否有关于单元测试 GUI 代码的指南?它甚至有意义吗?

例如,我的应用中有图表。我一直无法弄清楚如何自动化图表的测试。 AFAIK 需要人眼来检查图表是否正确。

(我正在使用 Java Swing)

【问题讨论】:

Martin Fowler (martinfowler.com/eaaDev/uiArchs.html) 有一篇关于不同 GUI 架构的精彩文章。它描述了在单元测试方面的 GUI 架构权衡。 现在,这个问题最好在 programmers.stackexchange.com 上提出(并且可能在 Stack Overflow 上偏离主题,因为太宽泛了),但旧问题无法迁移。抛开它是否属于这里的问题,这个问题仍然是一个有趣而困难的问题。 如果有一些 GUI 代码和 JUnit 的例子会很棒。 我想说放松一下,不要打扰。投入到单元测试中的努力并不总能带来净生产力。 老问题,你可以在GUI中使用Jubula测试流程 【参考方案1】:

MVP 和 MVC 等设计通常会尝试从实际 GUI 中抽象出尽可能多的逻辑。 Michael Feathers 的一篇非常受欢迎的文章是"The Humble Dialog Box"。就我个人而言,我在尝试将逻辑从 UI 中移出时有着不同的经历——有时它工作得很好,而在其他时候,它的麻烦多于它的价值。不过,这有点超出了我的专业领域。

【讨论】:

??? “有时它工作得很好,有时它比它的价值更麻烦”很奇怪,因为大多数新语言往往是面向 MVC 的......这是 gui(模型视觉)之外的逻辑......跨度> 不过,呈现逻辑仍将在 GUI 中。有时,这可能远非微不足道 镜像:The Humble Dialog Box Martin Fowler 对这个概念的处理(如果你的网络和我的一样,过滤archive.org):martinfowler.com/eaaDev/uiArchs.html#HumbleView @c24w 谢谢你拉了镜子,你才是真正的 MVP :)【参考方案2】:

当然,答案是使用 MVC 并将尽可能多的逻辑移出 GUI。

话虽如此,我很久以前从一位同事那里听说,当 SGI 将 OpenGL 移植到新硬件时,他们进行了一系列单元测试,这些单元测试会将一组基元绘制到屏幕上,然后计算 MD5 和帧缓冲区。然后可以将该值与已知的良好哈希值进行比较,以快速确定 API 是否按像素准确。

【讨论】:

我喜欢这种方法。设置和维护起来很麻烦,但它会给我我需要的回归测试功能。 dantel 你没抓住重点。 OpenGL 是一个像素精确的图形渲染 API。像 Qt 这样的 GUI 应用程序框架将高度依赖系统 chrome,因此散列帧缓冲区不是一个好方法。 一个MD5?加密哈希与此有什么关系?如何涉及安全?哈希,好的,对于像素完美的图形来说这是一个好主意,但是加密哈希?您可以使用更快的非加密哈希并且其冲突概率可以忽略不计。你确定这是一个加密哈希而不是简单的哈希吗? (除此之外,在这个并行计算的时代,不能并行化的哈希算法[用于非加密目的]应该被怀疑) @SyntaxT3rr0r:在这种与安全无关的应用程序中,您会推荐什么哈希函数,与 MD5 相比,您可以期待什么样的性能提升? 你回答的意思是“从不设计你的 GUI,因此不要测试它”。酷。【参考方案3】:

你可以试试UISpec4J 是一个开源功能和/或单元测试库,用于基于 Swing 的 Java 应用程序...

【讨论】:

我已经开始使用 UISpec4J 一个月左右在 Java Swing GUI 上进行需求验证测试。到目前为止,我一直很喜欢它。 github.com/UISpec4J/UISpec4J 声明您的链接是官方网站,但在我看来并不那么官方。我看到的只是一个关于视频博客的博客 @lucidbrot 它曾经是:web.archive.org/web/20090304192541/http://www.uispec4j.org【参考方案4】:

有 Selenium RC,它将自动测试基于 Web 的 UI。它将记录动作并重播它们。您仍然需要逐步完成与 UI 的交互,因此这对覆盖率没有帮助,但它可以用于自动构建。

【讨论】:

【参考方案5】:

您可以尝试使用Cucumber 和Swinger 为Swing GUI 应用程序用简单的英语编写功能验收测试。 Swinger 在后台使用 Netbeans 的 Jemmy 库来驱动应用程序。

Cucumber 允许你编写这样的测试:

 Scenario: Dialog manipulation
    Given the frame "SwingSet" is visible
    When I click the menu "File/About"
    Then I should see the dialog "About Swing!"
    When I click the button "OK"
    Then I should not see the dialog "About Swing!"

看看这个Swinger video demo 看看它的实际效果。

【讨论】:

【参考方案6】:

这里有一些提示:

尝试从 GUI 中删除尽可能多的代码(具有控制器和模型对象),这样您就可以在没有 GUI 的情况下测试它们。

对于图形,您应该测试您提供给生成图形的代码的值。

【讨论】:

【参考方案7】:

测试是一种艺术形式。我同意应尽可能删除逻辑 GUI。然后我们可以将单元测试集中在那里。像其他任何测试一样,测试是为了降低风险。您并不总是需要测试所有内容,但很多时候最好的办法是在不同区域分解不同的测试。

另一个问题是你真正想在 UI 层测试什么。 UI 测试是最昂贵的测试,因为它通常需要更长的时间来创建、维护并且它是最脆弱的。如果您在尝试绘制线之前测试逻辑以知道坐标是否正确,那么您具体测试的是什么?如果要测试用红线绘制的图形。你能给它一个预定的坐标并测试某些像素是红色还是非红色?正如上面建议的位图比较工作,Selenium 但我的主要关注点不是过度测试 GUI,而是测试有助于创建 UI 的逻辑,然后关注 UI 的哪些部分中断或可疑,并关注少数测试在那里。

【讨论】:

【参考方案8】:

您可以使用JFCUnit 来测试您的 GUI,但图形可能更具挑战性。我曾多次拍摄我的 GUI 快照并自动将其与以前的版本进行比较。虽然这不提供实际测试,但它会在自动构建未能产生预期输出时提醒您。

【讨论】:

【参考方案9】:

我从您的问题中收集到的是,您正在寻找一种自动化方法来详细测试您的 GUI 行为,您提供的示例是测试曲线是否实际绘制正确。

单元测试框架提供了一种进行自动化测试的方法,但我认为您想要执行的测试类型是复杂的集成测试,用于验证大量类的正确行为,其中包括您的 GUI 工具包/库的类,您不应该对其进行测试。

您的选择很大程度上取决于您使用的平台/工具包/框架:例如,使用 Qt 作为其 GUI 框架的应用程序可以使用 Squish 来自动化其测试。您只需验证一次测试结果,随后自动执行的测试就会将结果与验证结果进行比较。

【讨论】:

【参考方案10】:

Window Licker 用于 Swing 和 Ajax

【讨论】:

【参考方案11】:

我的 GUI 测试方法在不断发展,行业共识也在不断发展。但我认为一些关键技术正在开始出现。

我会根据具体情况使用这些技术中的一种或多种(例如,它是什么类型的 GUI、需要多快构建它、最终用户是谁等)。

    手动测试。 在处理代码时始终运行 GUI,并确保它与代码同步。您在工作时手动测试和重新测试您工作的部分,在代码和正在运行的应用程序之间切换。每次完成一些重要的工作时,都要对应用程序的整个屏幕或区域进行全面测试,以确保没有退步。

    单元测试。您为功能或 GUI 行为的小单元编写测试。例如,您的图表可能需要根据“基础”颜色计算颜色的不同深浅。您可以将此计算提取到函数并为其编写单元测试。您可以在 GUI 中搜索这样的逻辑(尤其是可重用的逻辑)并将其提取到离散的函数中,这样可以更容易地进行单元测试。即使是复杂的行为也可以通过这种方式进行提取和测试——例如,可以将向导中的一系列步骤提取到一个函数中,并且单元测试可以验证在给定输入的情况下是否返回了正确的步骤。

    组件浏览器。您创建一个“浏览器”屏幕,其唯一作用是展示构成您的 GUI 的每个可重用组件。此屏幕为您提供了一种快速简便的方法来直观地验证每个组件是否具有正确的外观和感觉。组件浏览器比手动浏览整个应用程序更有效,因为 A)您只需验证每个组件一次,并且 B)您不必深入应用程序来查看组件,您只需查看和立即验证。

    自动化测试。您编写一个与屏幕或组件交互的测试,模拟鼠标点击、数据输入等,断言应用程序在这些操作下正确运行。这可以用作额外的备份测试,以捕获其他测试可能遗漏的潜在错误。我倾向于为最容易损坏和/或非常关键的 GUI 部分保留自动化测试。如果有什么东西坏了,我想尽早知道的部分。这可能包括高度复杂的交互式组件,这些组件容易损坏或重要的主屏幕。

    差异/快照测试。您编写的测试只是将输出捕获为屏幕截图或 HTML 代码,并将其与之前的输出进行比较。这样,每当输出发生变化时,您都会收到提醒。如果您的 GUI 的视觉方面很复杂和/或可能发生变化,则差异测试可能很有用,在这种情况下,您需要快速直观地反馈给定变化对整个 GUI 的影响。

我更愿意根据我正在做的事情来挑选和选择测试技术,而不是粗暴地使用每一种可能的测试。因此,在一种情况下,我将提取一个简单的函数并对其进行单元测试,但在另一种情况下,我将向组件资源管理器中添加一个组件,等等。这取决于具体情况。

我还没有发现代码覆盖率是一个非常有用的指标,但其他人可能已经发现了它的用途。

我认为第一个衡量标准是错误的数量和严重程度。您的首要任务可能是拥有一个正常运行的应用程序。如果应用程序正常运行,则应该很少或没有错误。如果有很多或严重的错误,那么可能是您没有进行测试,或者您的测试无效。

除了减少错误之外,还有其他衡量标准,例如性能、可用​​性、可访问性、可维护性、可扩展性等。这些会有所不同,具体取决于您正在构建的应用程序类型、业务、最终用户等.

这一切都是基于我的个人经验和研究,以及 Ham Vocke 在 UI Tests 上的精彩文章。

【讨论】:

【参考方案12】:

据我所知,这相当复杂,并且真的取决于语言 - 许多语言都有自己的测试 GUI 的方式,但如果你真的需要测试 GUI(而不是模型/GUI 交互),你经常要模拟一个实际的用户点击按钮。例如,Eclipse 中使用的 SWT 框架提供了SWTBot,JFCUnit 已经提到过,Mozilla 在 XUL 中有自己的模拟方式(从我在他们的博客上看到的,这些测试似乎相当脆)。

有时您必须截取屏幕截图并测试像素完美渲染(我相信 Mozilla 这样做是为了检查正确渲染的页面) - 这需要更长的设置,但可能是您需要的图表。这样,当您更新代码并且测试中断时,您必须手动检查图像是否失败,或者您改进了图形渲染代码以生成更漂亮的图形并需要更新屏幕截图。

【讨论】:

【参考方案13】:

如果您使用的是 Swing,FEST-Swing 对于驱动您的 GUI 和测试断言很有用。它使测试诸如 “如果我单击按钮 A,应该显示对话框 B”“如果我从下拉列表中选择选项 2,所有复选框都应该变得非常简单取消选择”

您提到的图形场景并不是那么容易测试。仅通过创建和显示 GUI 组件(并且可能使用 FEST 驱动它们)就可以很容易地获得 GUI 组件的代码覆盖率。然而,做出有意义的断言是困难的部分(没有有意义的断言的代码覆盖是一种自欺欺人的练习)。您如何测试图表是否没有倒置或太小?

我认为您只需要接受 GUI 的某些方面无法通过自动化单元测试进行有效测试,您将不得不以其他方式对其进行测试。

【讨论】:

【参考方案14】:

测试 GUI 库不是您的工作。因此,您可以避开检查屏幕上实际绘制的内容的责任,而改为检查小部件的属性,相信库可以准确地表示所绘制的内容。

【讨论】:

以上是关于如何对 GUI 进行单元测试?的主要内容,如果未能解决你的问题,请参考以下文章

我如何对这样的代码进行单元测试?

PyQt.QTableView 内容的单元测试

如何在单元测试中模拟基于 MFC 的 GUI 功能的失败?

iOS 单元测试:如何对 firstResponderStatus 进行单元测试

如何对 ETL 流程进行测试(单元测试)?

如何在订阅Angular7单元测试用例中对代码进行单元测试