AI Agent、AI Infra、RAG 、出海合规,2024 前瞻性和实用性技术案例都在这里了 了解详情
写点什么

Maven 实战(五)——自动化 Web 应用集成测试

  • 2011-03-13
  • 本文字数:4677 字

    阅读完需:约 15 分钟

自动化集成测试的角色

本专栏的上一篇文章讲述了 Maven 与持续集成的一些关系及具体实践,我们都知道,自动化测试是持续集成必不可少的一部分,基本上,没有自动化测试的持续集成,都很难称之为真正的持续集成。我们希望持续集成能够尽早的暴露问题,但这远非配置一个 Hudson/Jenkins 服务器那么简单,只有真正用心编写了较为完整的测试用例,并一直维护它们,持续集成才能孜孜不倦地运行测试并第一时间报告问题。

自动化测试这个话题很大,本文不想争论测试先行还是后行,这里强调的是测试的自动化,并基于具体的技术(Maven、 JUnit、Jetty 等)来介绍一种切实可行的自动化 Web 应用集成测试方案。当然,自动化测试还包括单元测试、验收测试、性能测试等,在不同的场景下,它们都能为软件开发带来极大的价值。本文仅限于讨论集成测试,主要是因为笔者觉得这是一个非常重要却常常被忽略的实践。

基于 Maven 的一般流程

集成测试与单元测试最大的区别是它需要尽可能的测试整个功能及相关环境,对于测试 Web 应用而言,通常有这么几步:

  1. 启动 Web 容器
  2. 部署待测试 Web 应用
  3. 以 Web 客户端的角色运行测试用例
  4. 停止 Web 容器

启动 Web 容器可以有很多方式,例如你可以通过 Web 容器提供的 API 采用编程的方式来启动容器,但在 Maven 的环境下,配置插件显得更简单。如果你了解 Maven 的生命周期模型,就可能会想到,我们可以在 pre-integration-test 阶段启动容器,部署待测试应用,然后在 integration-test 阶段运行集成测试用例,最后在 post-integrate-test 阶段停止容器。也就是说,对于步骤 1,2 和 4 我们只须进行一些简单的配置,不必编写额外的代码。第 3 步是以黑盒的形式模拟客户端进行测试,需要注意的是,这里通常要求你理解一些基本的 HTTP 协议知识,例如服务端在什么情况下应该返回 HTTP 代码 200,什么时候应该返回 401 错误,以及所支持的 Content-Type 是什么等等。

至于测试用例该怎么写,除了需要用到一些用来访问 Web 以及解析响应详细的基础设施工具类之外,其他内容与单元测试大同小异,基本就是准备测试数据、访问服务、验证返回值等等。

一个简单的例子

谈了不少理论,现在该给个具体的例子了,譬如现在有个简单的 Servlet,它接受参数 a 和 b,做加法后返回二者之和,如果参数不完整,则返回 HTTP 400 错误,表示客户端的请求有问题。

复制代码
public class AddServlet
extends HttpServlet
{
@Override
protected void doGet( HttpServletRequest req, HttpServletResponse resp )
throws ServletException,
IOException
{
String a = req.getParameter( "a" );
String b = req.getParameter( "b" );
if ( a == null || b == null )
{
resp.setStatus( 400 );
return;
}
int result = Integer.parseInt( a ) + Integer.parseInt( b );
resp.setStatus( 200 );
resp.getWriter().print( result );
}
}

为了测试这段代码,我们需要一个 Web 容器,这里暂且使用 Jetty,因为目前来说它与 Maven 集成的相对最好。Jetty 提供了一个 Jetty Maven Plugin ,借助该插件,我们可以随时启动 Jetty 并部署 Maven 默认目录布局的 Web 项目,实现快速开发和测试。这里我们需要的是在 pre-integration-test 阶段启动 Jetty,在 post-integrate-test 阶段停止容器,对应的 POM 配置如下:

复制代码
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>jetty-maven-plugin</artifactId>
<version>7.3.0.v20110203</version>
<configuration>
<stopPort>9966</stopPort>
<stopKey>stop-jetty-for-it</stopKey>
</configuration>
<executions>
<execution>
<id>start-jetty</id>
<phase>pre-integration-test</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<daemon>true</daemon>
</configuration>
</execution>
<execution>
<id>stop-jetty</id>
<phase>post-integration-test</phase>
<goals>
<goal>stop</goal>
</goals>
</execution>
</executions>
</plugin>

XML 代码中第一处 configuration 是插件的全局配置,stopPort 和 stopKey 是该插件用来停止 Jetty 需要用到的 TCP 端口及消息关键字。接着是两个 executation 元素,第一个 executation 将 jetty-maven-plugin 的 run 目标绑定至 Maven 的 pre-integration-test 生命周期阶段,表示启动容器,第二个 executation 将 stop 目标绑定至 post-integration-test 生命周期阶段,表示停止容器。需要注意的是,启动 Jetty 时我们需要配置 deamon 为 true,让 Jetty 在后台运行以免阻塞 mvn 命令。此外,jetty-maven-plugin 的 run 目标也会自动部署当前 Web 项目。

准备好 Web 容器环境之后,我们接着看一下测试用例代码:

复制代码
public class AddServletIT
{
@Test
public void addWithParametersAndSucceed()
throws Exception
{
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet( "http://localhost:8080/add?a=1&b=2" );
HttpResponse response = httpclient.execute( httpGet );
Assert.assertEquals( 200, response.getStatusLine().getStatusCode() );
Assert.assertEquals( "3", EntityUtils.toString( response.getEntity() ) );
}
@Test
public void addWithoutParameterAndFail()
throws Exception
{
HttpClient httpclient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet( "http://localhost:8080/add" );
HttpResponse response = httpclient.execute( httpGet );
Assert.assertEquals( 400, response.getStatusLine().getStatusCode() );
}
}

为了能够访问应用,这里用到了 HttpClient ,两个测试方法都初始化一个 HttpClient,然后创建 HttpGet 对象用来访问 Web 地址。第一个测试方法顾名思义用来测试成功的场景,它提供参数 a=1 和 b=2,执行请求后,验证返回结果成功(HTTP 状态码 200)并且内容为正确的值 3。第二个测试方法则用来测试失败的场景,当不提供参数的时候,服务器应该返回一个 HTTP 400 错误。该测试类其实是相当粗糙的,例如有硬编码的服务器 URL,这里的目的仅仅是通过尽可能简单的代码来展现一个自动化集成测试的实现过程。

上述代码中,测试类的名称为 AddServletIT,而不是一般的 **Test,IT 表示 IntegrationTest,这么命名是为了和单元测试区分开来,这样,鉴于 Maven 默认的测试命名约定,Maven 在 test 生命周期阶段执行单元测试时,就不会涉及集成测试。现在,我们希望 Maven 在 integration-test 阶段执行所有以 IT 结尾命名的测试类,配置 Maven Surefire Plugin 如下:

复制代码
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.7.2</version>
<executions>
<execution>
<id>run-integration-test</id>
<phase>integration-test</phase>
<goals>
<goal>test</goal>
</goals>
<configuration>
<includes>
<include>**/*IT.java</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>

通过命名规则和插件配置,我们优雅地分离了单元测试和集成测试,而且我们知道在 integration-test 阶段,Jetty 容器已经启动完成了。如果你在使用 TestNG,那你还可以使用其测试组的特性来分离单元测试和集成测试,Maven Surefire Plugin 对其也有着很好的支持

一切就绪了,运行 mvn clean install 以自动运行集成测试,我们可以看到如下的输出片段:

复制代码
[INFO] --- jetty-maven-plugin:7.3.0.v20110203:run (start-jetty) @ webapp-demo ---
[INFO] Configuring Jetty for project: webapp-demo
[INFO] webAppSourceDirectory /home/juven/git_juven/webapp-demo/src/main/webapp does not exist. Defaulting to /home/juven/git_juven/webapp-demo/src/main/webapp
[INFO] Reload Mechanic: automatic
[INFO] Classes = /home/juven/git_juven/webapp-demo/target/classes
[INFO] Context path = /
...
2011-03-06 14:55:15.676:INFO::Started SelectChannelConnector@0.0.0.0:8080
[INFO] Started Jetty Server
[INFO]
[INFO] --- maven-surefire-plugin:2.7.2:test (run-integration-test) @ webapp-demo ---
[INFO] Surefire report directory: /home/juven/git_juven/webapp-demo/target/surefire-reports
-------------------------------------------------------
T E S T S
-------------------------------------------------------
Running com.juvenxu.webapp.demo.AddServletIT
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.344 sec
Results :
Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
[INFO]
[INFO] --- jetty-maven-plugin:7.3.0.v20110203:stop (stop-jetty) @ webapp-demo ---

可以看到 jetty-maven-plugin:7.3.0.v20110203:run 对应了 start-jetty,maven-surefire- plugin:2.7.2:test 对应了 run-integration-test,jetty-maven- plugin:7.3.0.v20110203:stop 对应了 stop-jetty,与我们的配置和期望完全一致。此外两个测试也都成功了!

小结

相对于单元测试来说,集成测试更难编写,因为需要准备更多的环境,本文只涉及了Web 容器最简单的情形,实际的开发情形中,你可能会遇到数据库,第三方Web 服务,更复杂的容器配置和数据格式等等,这都使得编写集成测试变得让人畏惧。然而反过来考虑,无论如何你都需要测试,虽然这个自动化过程的投入很大,但收益往往更加客观,这不仅仅是手动测试时间的节省,更重要的是,你无法保证手动测试能被高频率的反复执行,也就无法保证问题能被尽早暴露。

对于Web 应用来说,编写集成测试有助于你考虑和设计Web 应用对外暴露的接口,这种“开发实现”/“测试审察”之间的角色转换往往能造就更清晰的设计,这也是编写测试最大的好处之一。

Maven 用户能够得益于 Maven 的插件系统,不仅能节省大量的编码,还能得到稳定的工具,Jetty Maven Plugin 和 Maven Surefire Plugin 就是最好的例子。本文只涉及了 Jetty,如果读者的环境是 Tomcat 或者 JBoss 等其他容器,则需要查阅相关的文档以得到具体的实现细节,你可能对 Tomcat Maven Plugin JBoss Maven Plugin 、或者 Cargo Maven2 Plugin 感兴趣。

关于作者

许晓斌(Juven Xu),国内社区公认的 Maven 技术专家、Maven 中文用户组创始人、Maven 技术的先驱和积极推动者。对 Maven 有深刻的认识,实战经验丰富,不仅撰写了大量关于 Maven 的技术文章,而且还翻译了开源书籍《Maven 权威指南》,对 Maven 技术在国内的普及和发展做出了很大的贡献。就职于 Maven 之父的公司,负责维护 Maven 中央仓库,是 Maven 仓库管理器 Nexus(著名开源软件)的核心开发者之一,曾多次受邀到淘宝等大型企业开展 Maven 方面的培训。此外,他还是开源技术的积极倡导者和推动者,擅长 Java 开发和敏捷开发实践。他的个人网站是: http://www.juvenxu.com

2011-03-13 00:1518314

评论

发布
暂无评论
发现更多内容

Java中的代码重构:技巧、优秀实践与方法

这我可不懂

Java 代码重构

云端聚首,造炬成阳 | 瑞技荣获思科云CCC合作伙伴授牌

Bytebridge

倒计时 2 天!本周六,Apache Doris 年度技术盛会相约北京!

SelectDB

数据库 大数据 数据仓库 实时数仓 apache doris

红楼梦人物关系图怎么画?超详细的人物关系图绘制教程来了。

彭宏豪95

阅读 在线白板 办公软件 绘图软件 绘图工具

Zbrush 2023(数字雕刻和绘画程序)激活版mac/win

iMac小白

ZBrush破解版 ZBrush2023 ZBrush下载

区块链支持物联网的4种方式

BSN研习社

泛微全新低代码平台e-builder发布,让应用构建更智能、协同、全程数字化

Geek_2d6073

基于虚拟仿真技术的汽车燃油泵控制

DevOps和数字孪生

数字孪生 虚拟仿真 汽车行业

谈国产替代---从新出发

统信软件

操作系统 国产化替代

ScreenFlow for mac(屏幕录像软件) v10.0.9汉化版

iMac小白

ScreenFlow汉化版 ScreenFlow下载 ScreenFlow破解版 ScreenFlow mac

JetBrains PhpStorm 2023中文激活版mac/win

iMac小白

PhpStorm 2023下载 PhpStorm 2023破解版 PhpStorm 2023注册码 PhpStorm mac

Javascript抓取京东、淘宝商品数据

Noah

软件研发降本增效:寻求高效研发团队还是选择软件外包?

SoFlu软件机器人

软件开发 软件定制

突破放量困境:百度营销放量神器的高级应用指南!

Geek_2d6073

数字孪生:助力机载软件构型管理

DevOps和数字孪生

数字孪生 机载软件

使用 Jenkins 与 KubeVela 实现应用的持续交付

高端章鱼哥

JavaScript node.js API

平台工程动态 Monthly News 2023-9

杨振涛

DevOps 云原生 开发者体验 内部开发者平台 平台工程,

QCN9024 Performance|WiFi6E TriBand Card DR9074 Achieving Blazing 1.3Gbps Speed in 5.28GHz 80MHz BW Throughput Test

wallyslilly

QCN9074 QCN9024

博睿数据 Bonree ONE 秋季产品发布会,即将震撼启幕!

博睿数据

可观测性 博睿数据 智能化平台

语音识别技术中的实时处理与云计算

来自四九城儿

微信防撤回 WeChatTweak 最新集成版

iMac小白

微信多开 微信助手 微信消息撤回

语音识别技术在智能家居中的应用与挑战

来自四九城儿

语音识别技术在医疗领域的应用与前景

来自四九城儿

PHP-FFMpeg 操作音视频

极客飞兔

php 音视频 ffmpeg 经验总结

IBM SPSS Statistics 26 (spss统计软件)中文特别版mac/win

iMac小白

IBM SPSS Statistics中文 IBM SPSS Statistics 26 spss统计软件

Maven实战(五)——自动化Web应用集成测试_Java_许晓斌_InfoQ精选文章