测试
这是 “使用 Android Studio 开发 Web 程序” 系列的最后一篇文章,接着前一篇调试的主题之后要进行的是测试。不是已经可以调试了? 调试就是在测试了啊? 还要研究什么? 有这样疑问的人可以先参考一下这一篇文章。
研究的方向是希望能够确认在 Android Studio 进行测试时,可以满足下几项测试上的需求:
- 自动化
不仅仅是在开发时能够大幅减少测试这项工作的负担,并且还要能够把自动化延续到 CI 系统中,以便有效提升整体的开发工作品质。 - Code Coverage
作为测试完成度的一项指标,借以调整测试程序开发的策略、投入的成本及风险的控管。 - Data Driven
用来与测试的策略搭配以提升 Code Coverage,并且可以将造成系统运作问题的数据保留下来,成为一个收集系统问题的机制,成为回归测试的基准之一。
在 Android Studio 里就已内建了对 JUnit 和 TestNG 的支持,所以只要按照这些 Framework 的规格写好测试类,并且把文件存在对应 Module 的 src/test 文件夹之下,IDE 就会自动识别出来。IDE 也有提供对应的功能来简化测试的产生程序,相关的细节可以参考官网的 Creating Tests 及 Creating Test Methods。
有了测试的程序,接下来要确认是否能够达成自动化的需求。首先,要启动测试的话,透过 IDE 就可以轻易的达成,运行的细节可以参考官网的 Creating Run/Debug Configuration for Tests 及 Performing Tests 的说明文件。测试的结果会直接显示在 IDE 的介面上,但要先确定 “Show Statistics” 的选项是否开启,否则只会看到运行后的输出结果。要如何开启 “Show Statistics” 选项可以参考官网 Viewing and Exploring Test Results 的说明文件。
由 Run/Debug Configuration 的设定画面可以发现,和 Eclipse 相同,可以设定要运行测试的范围。所以只要设定好适当的选项,即可在 IDE 中一键运行所有的测试来达成开发阶段的测试自动化。与 CI 系统整合的部分,既然是 Gradle 的专案,当然是运行 test 或是有包含 test 的 Task 来达到目的,由相关的功能来看自动化的需求已经能够满足。
在编写源代码的系列文章中有提到,IDE 的介面上就可以直接运行 Gradle 专案的 Task,和在 Terminal 下指令相同,都会产生 HTML 格式的测试报告在对应 Module 的 build/reports/tests 文件夹下。但如果是在 Terminal 下指令则要自行用浏览器开启测试报告的 HTML 档,而使用 IDE 运行 Task 则可以在 IDE 中检视测试的结果,并点选如下图所示的 “Open Gradle test report” 图标启动并显示测试报告的内容。
而与测试有着密切关连的 Code Coverage 需求,由于 Android Studio 内建就有整合了 Code Coverage 的功能,所以只要是属于测试类型的 Configuration 项目都可以使用 “Run 'xxx' with Coverage” 的功能,如果不是测试类型的 Configuration 项目在 Toolbar 上的图标会被 Disable。相关的操作细节可以参考官网的 Running with Coverage 及 Viewing Code Coverage Results 的说明文件。
最后一项需求是 Data Driven,在 Android Studio 所支持的 JUnit 和 TestNG 都有提供特定的方法来达成目的。但在这里有一个比较不一样的选择:Spock,对,就是那个尖耳朵、瓜呆头的半 Vulcan 星人的名字。这是一个和 JUnit 相容的测试框架,也就是说可以无缝式地被整合在支持 JUnit 的 IDE 中,再说得白话一点就是可以在 Android Studio 里使用 JUnit 的 Configuration 项目运行 Spock 的测试程序、产出测试报告、运行 Code Coverage 等。
为什么为想要使用 Spock 来做为测试的框架?主要是长久以来软件设计的生命周期里,需求和程序之间都有一道明显的鸿沟,原因是主流的程序语言还没有进化到可以使用自然语言来表达,所以就需要靠程序撰写人员来转译,把需求文件中的文字转成可运行的源代码。就算是导入 TDD 来协助开发,源代码可以透过先写好的测试程序来检查是否符合需求,然而目前的测试程序也还都是相同的程序语言所构成的,需求里描述的情境还是要再被转一手。
转换就会有出现落差的风险,但是 Spock 使用 BDD 的概念填补了需求文件和测试程序间的差距,让测试案例可以不被大幅转译的情况下,在测试源代码中以接近自然语言的语法来呈现 (可惜是当然地使用英文的语法),使转译失真的风险有效地被降低。就 Spock 这项特色来说,可以让文件和测试建立直接的关连并且用来验证实作的结果,是相当具有吸引力的。当然,Spock 也可以使用 Data Driven 的方式来撰写测试程序,而且能够以更直觉的的式来建立测试时所需的数据。
Spock 的测试类别是以 Groovy 为基础,要在原本是 Java 的 Module 上使用 Groovy 要先设定让 Module 支持 Groovy,详细的操作步骤可以参考官网的 Configuring Groovy-Based Frameworks 说明文件。并且在 build.gradle 里应该包含以下示范的内容:
dependencies {
testCompile 'org.codehaus.groovy:groovy-all:2.3.3'
testCompile 'org.spockframework:spock-core:0.7-groovy-2.0'
}
在使用 Data Driven 产出的测试报告时有一个要注意的细节,通常测试报告显示的单位都是以测试项目为基准,但由于 Data Driven 是在一个单一的测试项目中重覆地输入不同数据的方式来进行。在使用 Data Driven 产出的测试报告没有办法显示每一个受测数据样本的测试结果时,会造成阅读报告时一个很大的困扰。因为使用的样本数有可能成百上千组,当测试报告显示某个项目测试失败,但却无法显示造成失败的数据样本,甚至连失败样本组数都没有的话,错误根本就无从定位,也没有办法被修正。
在 Spock 中提供了一个 @Unroll 的 Annotation,可以让测试报告显示的项目揭露到每一组数据样本的层级。透过 Gradle 的 test Task 产出的报告档就会根据这个 Annotation 调整内容,将原本以测试项目为单位改为以受测的样本组为单位。
但在 Android Studio 里会有一个小状况是,如果只单独运行一个测试类别,在 Statistics 里可以检视到每一组数据样本的测试结果。当同时运行多个类别的测试,Statistics 检视不到相同的结果。所以这时可能就不能使用 JUnit 的 Configuration 来运行测试,要改为 Gradle 的 Configuration,并且在浏览器中来检视测试报告。
截至目前为止,研究的结果大致都符合原先设定的需求条件,所以可以暂时完全先放下 Eclipse,开开心心地使用 Android Studio 上工啰!