如何对GUI进行单元测试?


154

我的代码中的计算经过了充分的测试,但是由于有太多的GUI代码,所以我的总体代码覆盖范围比我想要的低。是否有关于单元测试GUI代码的准则?有道理吗?

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

(我正在使用Java Swing)


1
Martin Fowler(martinfowler.com/eaaDev/uiArchs.html)发表了一篇有关不同GUI架构的精彩文章。它从单元测试的角度描述了GUI体系结构的权衡。
罗曼·黄

1
如今,最好在programmers.stackexchange.com上问这个问题(由于太宽泛,它可能在Stack Overflow上是个话题),但是旧的问题无法移植。问题是否放在这里,这个问题仍然是一个有趣且困难的问题。
Mark Amery 2014年

1
带有一些GUI代码段和JUnit的示例将是很棒的。
Witold Kaczurba '16

1
我会说只是放松,不要打扰。进行单元测试的工作并不总是能产生净成果。
codeulike

仍然是一个老问题,您可以使用Jubula
Abi,

Answers:


68

MVP和MVC之类的设计通常尝试从实际GUI中提取尽可能多的逻辑。关于这一点的一篇非常受欢迎的文章是Michael Feathers的“谦虚对话框”。就个人而言,我在尝试将逻辑移出UI时有过多种经验-有时效果非常好,而在其他时候,麻烦已超出其价值。不过,这有点超出我的专业领域。


??? “有时它工作得很好,而在另一些时候则比它值得的麻烦得多。”很奇怪,因为大多数新语言都倾向于面向MVC……这是gui(Model-Visual)的逻辑……
Patrick Desjardins

14
表示逻辑仍将在GUI中。有时,这可能并不容易
安德里亚(Andrea)2012年


马丁·福勒(Martin Fowler)对概念的处理(以防您的网络(如我的网络,过滤器archive.org)):martinfowler.com/eaaDev/uiArchs.html#HumbleView
Christopher Berman,

@ c24w感谢您拉那个镜子,您才是真正的MVP :)
John Baker

38

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

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


3
我喜欢这种方法。设置和维护很麻烦,但是它将为我提供所需的回归测试功能。
史蒂夫·麦克劳德

7
达纳特尔,你错过了重点。OpenGL是像素精确的图形渲染API。Qt之类的GUI应用程序框架将高度依赖于系统镶边,因此对帧缓冲区进行散列并不是一个好方法。
鲍勃·萨默斯

1
MD5?与此相关的密码哈希是什么?如何涉及安全性?哈希,好吧,对于像素完美的图形来说这是个好主意,但是密码哈希呢?您可以使用非加密且冲突概率可以忽略的更快的哈希。您确定这是加密哈希,而不仅仅是哈希吗?(此外,在当今并行计算的时代,应该怀疑不能并行化的哈希算法(用于非加密目的)应予以怀疑)
SyntaxT3rr0r 2010年

24
@ SyntaxT3rr0r:在这种类型的与安全无关的应用程序中,您会建议使用哪种哈希函数?与MD5相比,您可以期望获得什么样的性能提升?
冒犯君主

1
您回答的意思是“永远不要设计GU​​I并因此不要对其进行测试”。凉。
2015年

10

您可以尝试UISpec4J是针对基于Swing的Java应用程序的开源功能和/或单元测试库...


2
我已经开始使用UISpec4J一个月左右的时间来在Java Swing GUI上进行需求验证测试。到目前为止,我一直很喜欢。
巴萨姆

github.com/UISpec4J/UISpec4J声明您的链接是官方网站,但对我而言,它看起来并不官方。我所看到的只是一个有关博客的博客
lucidbrot

7

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


7

您可以尝试使用CucumberSwinger用普通的英语编写针对Swing GUI应用程序的功能接受测试。Swinger在后台使用Netbeans的Jemmy库来驱动该应用程序。

黄瓜允许您编写如下测试:

 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视频演示以实际操作。


6

这里有一些提示:

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

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


6

测试是一种艺术形式。我同意应尽可能删除GUI的逻辑。然后,我们可以集中进行单元测试。像其他任何东西一样,测试都是关于降低风险的。您不一定总是需要测试所有内容,但是很多时候,最好的办法是分解针对不同区域的不同测试。

另一个问题是您到底想在UI层测试什么。UI测试是最昂贵的测试,因为它通常需要更长的时间来创建,维护和最脆弱。如果您在尝试画线之前测试逻辑以了解坐标正确,那么您要具体测试什么?如果要测试,则用红线绘制图形。您可以给它设置一个预定的坐标并测试某些像素是否为红色?正如上面的位图比较建议的那样,Selenium但我的主要重点不是过度测试GUI,而是测试有助于创建UI的逻辑,然后关注UI的哪一部分损坏或可疑,并集中进行少量测试那里。


3

您可以使用JFCUnit测试您的GUI,但是图形可能更具挑战性。我有几次为我的GUI拍摄快照,并自动将其与以前的版本进行比较。虽然这没有提供实际的测试,但是会在自动构建无法产生预期输出的情况下提醒您。


3

从您的问题中得出的结论是,您正在寻找一种自动化的方法来详细测试您的GUI行为,您所提供的示例是测试曲线是否正确绘制。

单元测试框架提供了一种进行自动化测试的方法,但是我认为您想要进行的测试是复杂的集成测试,这些测试可以验证许多类的正确行为,其中包括您的GUI工具箱/库的类。不应该测试。

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



2

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

根据情况(例如,它是哪种GUI,需要多快构建,最终用户是谁等),我将使用其中的一种或多种技术。

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

  2. 单元测试。您可以针对功能或小型GUI行为编写测试。例如,您的图形可能需要根据“基本”颜色计算出不同的颜色阴影。您可以将该计算结果提取到函数中并为其编写单元测试。您可以在GUI中搜索类似的逻辑(尤其是可重用的逻辑),并将其提取到谨慎的功能中,从而可以更轻松地进行单元测试。甚至可以以这种方式提取和测试复杂的行为-例如,可以将向导中的一系列步骤提取到函数中,而单元测试可以验证给定输入是否返回了正确的步骤。

  3. 组件资源管理器。您创建一个“资源管理器”屏幕,其唯一作用是展示构成GUI的每个可重用组件。该屏幕为您提供了一种快速简便的方法,可以直观地验证每个组件的外观和感觉。与手动浏览整个应用程序相比,组件浏览器效率更高,因为A)您只需要验证每个组件一次,B)您无需深入应用程序即可查看组件,只需查看和查看即可。立即验证。

  4. 自动化测试。您编写了一个与屏幕或组件交互的测试,模拟了鼠标单击,数据输入等,并断言在进行这些操作后应用程序可以正常运行。这可以用作额外的备份测试,以捕获其他测试可能遗漏的潜在错误。我倾向于为GUI中最容易出现故障和/或非常关键的部分保留自动化测试。我想尽早知道零件是否损坏的零件。这可能包括高度复杂的交互式组件,这些组件很容易损坏或损坏重要的主屏幕。

  5. 差异/快照测试。您编写了一个仅将输出捕获为屏幕截图或HTML代码并将其与先前输出进行比较的测试。这样,只要输出发生更改,您就会收到警报。如果GUI的视觉方面很复杂和/或可能发生更改,则差异测试可能会很有用,在这种情况下,您需要快速直观的反馈,以了解给定更改对GUI整体的影响。

我宁愿费力地使用每种可能的测试方法,而不会根据自己正在从事的工作来选择测试技术。因此,在一种情况下,我将提取一个简单的函数并对它进行单元测试,但在另一种情况下,我将向组件资源管理器中添加一个组件,依此类推。

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

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

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

这些都是基于我的个人经验和研究以及Ham Vocke撰写的关于UI测试出色文章


1

据我所知,这是相当复杂的,并且实际上取决于语言-许多语言都有自己的GUI测试方法,但是如果您确实需要测试GUI(而不是模型/ GUI交互),则通常必须模拟实际用户单击按钮。例如,Eclipse中使用的SWT框架提供了SWTBotJFCUnit已经提到了,Mozilla有他们自己的在XUL中进行模拟的方式(从我在他们的博客上所读的内容来看,这些测试似乎很脆弱)。

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


0

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

您提到的图形方案不太容易测试。仅通过创建和显示GUI组件(并可能通过FEST驱动)就可以很容易地获得GUI组件的代码覆盖率。但是,做出有意义的断言是困难的部分(而没有有意义断言的代码覆盖范围是自欺欺人的一种练习)。您如何测试图形不是上下颠倒还是太小?

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


0

测试GUI库不是您的工作。因此,您可以逃避检查屏幕上实际绘制的内容并检查小部件的属性的责任,并信任库,它们可以准确地代表绘制的内容。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.