我的代码中的计算经过了充分的测试,但是由于有太多的GUI代码,所以我的总体代码覆盖范围比我想要的低。是否有关于单元测试GUI代码的准则?有道理吗?
例如,我的应用程序中有图形。我还无法弄清楚如何自动化图形测试。需要人眼AFAIK来检查图形是否正确。
(我正在使用Java Swing)
我的代码中的计算经过了充分的测试,但是由于有太多的GUI代码,所以我的总体代码覆盖范围比我想要的低。是否有关于单元测试GUI代码的准则?有道理吗?
例如,我的应用程序中有图形。我还无法弄清楚如何自动化图形测试。需要人眼AFAIK来检查图形是否正确。
(我正在使用Java Swing)
Answers:
MVP和MVC之类的设计通常尝试从实际GUI中提取尽可能多的逻辑。关于这一点的一篇非常受欢迎的文章是Michael Feathers的“谦虚对话框”。就个人而言,我在尝试将逻辑移出UI时有过多种经验-有时效果非常好,而在其他时候,麻烦已超出其价值。不过,这有点超出我的专业领域。
当然,答案是使用MVC并将尽可能多的逻辑移出GUI。
话虽如此,我很久以前从同事那里听说,当SGI将OpenGL移植到新硬件上时,他们进行了一堆单元测试,这些单元测试会将一组原始函数绘制到屏幕上,然后计算帧缓冲区的MD5和。然后可以将该值与已知的良好哈希值进行比较,以快速确定API是否每个像素准确。
有Selenium RC,它将自动测试基于Web的UI。它将记录动作并重播它们。您仍然需要逐步完成与UI的交互,因此这对覆盖面无济于事,但可用于自动构建。
您可以尝试使用Cucumber和Swinger用普通的英语编写针对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视频演示以实际操作。
这里有一些提示:
尝试以这种方式从GUI(具有控制器和模型对象)中删除尽可能多的代码,这样就可以在没有GUI的情况下对其进行测试。
对于图形,您应该测试提供给生成图形的代码的值。
测试是一种艺术形式。我同意应尽可能删除GUI的逻辑。然后,我们可以集中进行单元测试。像其他任何东西一样,测试都是关于降低风险的。您不一定总是需要测试所有内容,但是很多时候,最好的办法是分解针对不同区域的不同测试。
另一个问题是您到底想在UI层测试什么。UI测试是最昂贵的测试,因为它通常需要更长的时间来创建,维护和最脆弱。如果您在尝试画线之前测试逻辑以了解坐标正确,那么您要具体测试什么?如果要测试,则用红线绘制图形。您可以给它设置一个预定的坐标并测试某些像素是否为红色?正如上面的位图比较建议的那样,Selenium但我的主要重点不是过度测试GUI,而是测试有助于创建UI的逻辑,然后关注UI的哪一部分损坏或可疑,并集中进行少量测试那里。
从您的问题中得出的结论是,您正在寻找一种自动化的方法来详细测试您的GUI行为,您所提供的示例是测试曲线是否正确绘制。
单元测试框架提供了一种进行自动化测试的方法,但是我认为您想要进行的测试是复杂的集成测试,这些测试可以验证许多类的正确行为,其中包括您的GUI工具箱/库的类。不应该测试。
您的选择在很大程度上取决于您使用的平台/工具包/框架:例如,使用Qt作为其GUI框架的应用程序可以使用Squish自动执行其测试。您只需验证一次测试结果,随后自动执行的测试就会将结果与验证后的结果进行比较。
我的GUI测试方法正在不断发展,业界共识也在不断发展。但是我认为一些关键技术已经开始出现。
根据情况(例如,它是哪种GUI,需要多快构建,最终用户是谁等),我将使用其中的一种或多种技术。
手动测试。在处理代码时,始终使GUI运行,并确保它与代码同步。您可以在工作时手动测试和重新测试工作的零件,在代码和正在运行的应用程序之间切换。每次完成一些重要的工作时,都对应用程序的整个屏幕或整个区域进行整体测试,以确保没有任何退步。
单元测试。您可以针对功能或小型GUI行为编写测试。例如,您的图形可能需要根据“基本”颜色计算出不同的颜色阴影。您可以将该计算结果提取到函数中并为其编写单元测试。您可以在GUI中搜索类似的逻辑(尤其是可重用的逻辑),并将其提取到谨慎的功能中,从而可以更轻松地进行单元测试。甚至可以以这种方式提取和测试复杂的行为-例如,可以将向导中的一系列步骤提取到函数中,而单元测试可以验证给定输入是否返回了正确的步骤。
组件资源管理器。您创建一个“资源管理器”屏幕,其唯一作用是展示构成GUI的每个可重用组件。该屏幕为您提供了一种快速简便的方法,可以直观地验证每个组件的外观和感觉。与手动浏览整个应用程序相比,组件浏览器效率更高,因为A)您只需要验证每个组件一次,B)您无需深入应用程序即可查看组件,只需查看和查看即可。立即验证。
自动化测试。您编写了一个与屏幕或组件交互的测试,模拟了鼠标单击,数据输入等,并断言在进行这些操作后应用程序可以正常运行。这可以用作额外的备份测试,以捕获其他测试可能遗漏的潜在错误。我倾向于为GUI中最容易出现故障和/或非常关键的部分保留自动化测试。我想尽早知道零件是否损坏的零件。这可能包括高度复杂的交互式组件,这些组件很容易损坏或损坏重要的主屏幕。
差异/快照测试。您编写了一个仅将输出捕获为屏幕截图或HTML代码并将其与先前输出进行比较的测试。这样,只要输出发生更改,您就会收到警报。如果GUI的视觉方面很复杂和/或可能发生更改,则差异测试可能会很有用,在这种情况下,您需要快速直观的反馈,以了解给定更改对GUI整体的影响。
我宁愿费力地使用每种可能的测试方法,而不会根据自己正在从事的工作来选择测试技术。因此,在一种情况下,我将提取一个简单的函数并对它进行单元测试,但在另一种情况下,我将向组件资源管理器中添加一个组件,依此类推。
我还没有发现代码覆盖率是一个非常有用的指标,但是其他人可能已经发现了它的用途。
我认为第一个衡量标准是错误的数量和严重性。您的首要任务可能是拥有一个运行正常的应用程序。如果应用程序正常运行,则应该很少或没有错误。如果存在许多或严重的错误,那么大概是您没有测试或测试无效。
除了减少错误外,还有其他指标,例如性能,可用性,可访问性,可维护性,可扩展性等。这些指标会有所不同,具体取决于您所构建的应用程序类型,业务,最终用户等。
据我所知,这是相当复杂的,并且实际上取决于语言-许多语言都有自己的GUI测试方法,但是如果您确实需要测试GUI(而不是模型/ GUI交互),则通常必须模拟实际用户单击按钮。例如,Eclipse中使用的SWT框架提供了SWTBot,JFCUnit已经提到了,Mozilla有他们自己的在XUL中进行模拟的方式(从我在他们的博客上所读的内容来看,这些测试似乎很脆弱)。
有时,您必须截屏并测试像素完美的渲染(我相信Mozilla这样做是为了检查是否正确渲染了页面)-这需要更长的设置,但可能是图形所需要的。这样,当您更新代码并中断测试时,您必须手动检查图像是否是真正的失败,或者您改进了图形渲染代码以生成更漂亮的图形并需要更新屏幕截图。
如果使用的是Swing,则FEST-Swing对于驱动GUI和测试断言很有用。它使测试诸如“如果我单击按钮A,应显示对话框B”或“如果我从下拉菜单中选择选项2,所有复选框都应取消选中”之类的事情变得非常简单。
您提到的图形方案不太容易测试。仅通过创建和显示GUI组件(并可能通过FEST驱动)就可以很容易地获得GUI组件的代码覆盖率。但是,做出有意义的断言是困难的部分(而没有有意义断言的代码覆盖范围是自欺欺人的一种练习)。您如何测试图形不是上下颠倒还是太小?
我认为您只需要接受GUI的某些方面无法通过自动化的单元测试进行有效测试,而您将不得不以其他方式对其进行测试。
测试GUI库不是您的工作。因此,您可以逃避检查屏幕上实际绘制的内容并检查小部件的属性的责任,并信任库,它们可以准确地代表绘制的内容。