Maven实战(五)——自己主动化Web应用集成測试
自己主动化集成測试的角色
本专栏的上一篇文章讲述了Maven与持续集成的一些关系及详细实践,我们都知道,自己主动化測试是持续集成不可缺少的一部分,基本上,没有自己主动化測试的持续集成,都非常难称之为真正的持续集成。我们希望持续集成可以尽早的暴露问题。但这远非配置一个 Hudson/Jenkinsserver那么简单,仅仅有真正用心编写了较为完整的測试用例。并一直维护它们,持续集成才干孜孜不倦地执行測试并第一时间报告问题。
自己主动化測试这个话题非常大,本文不想争论測试先行还是后行,这里强调的是測试的自己主动化,并基于详细的技术(Maven、 JUnit、Jetty等)来介绍一种切实可行的自己主动化Web应用集成測试方案。当然。自己主动化測试还包含单元測试、验收測试、性能測试等,在不同的场景下,它们都能为软件开发带来极大的价值。本文仅限于讨论集成測试,主要是由于笔者认为这是一个非常重要却经常被忽略的实践。
基于Maven的一般流程
集成測试与单元測试最大的差别是它须要尽可能的測试整个功能及相关环境,对于測试Web应用而言,通常有这么几步:
启动Web容器
部署待測试Web应用
以Webclient的角色执行測试用例
停止Web容器
启动Web容器能够有非常多方式。比如你能够通过Web容器提供的API採用编程的方式来启动容器,但在Maven的环境下,配置插件显得更简单。
假设你了解Maven的生命周期模型。就可能会想到,我们能够在pre-integration-test阶段启动容器,部署待測试应用。然后在integration-test阶段执行集成測试用例,最后在post-integrate-test阶段停止容器。
也就是说,对于步骤1,2和4我们仅仅须进行一些简单的配置,不必编写额外的代码。
第3步是以黑盒的形式模拟client进行測试,须要注意的是,这里通常要求你理解一些主要的HTTP协议知识,比如服务端在什么情况下应该返回HTTP代码
200,什么时候应该返回401错误,以及所支持的Content-Type是什么等等。
至于測试用例该怎么写,除了须要用到一些用来訪问Web以及解析响应具体的基础设施工具类之外。其它内容与单元測试大同小异。基本就是准备測试数据、訪问服务、验证返回值等等。
一个简单的样例
谈了不少理论,如今该给个详细的样例了,譬如如今有个简单的Servlet。它接受參数a和b。做加法后返回二者之和,假设參数不完整,则返回HTTP 400错误,表示client的请求有问题。
- 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须要用到的TCPport及消息keyword。接着是两个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。第二个測试方法则用来測试失败的场景。当不提供參数的时候。server应该返回一个HTTP 400错误。该測试类事实上是相当粗糙的,比如有硬编码的serverURL,这里的目的不过通过尽可能简单的代码来展现一个自己主动化集成測试的实现过程。
上述代码中,測试类的名称为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感兴趣。
原文地址:http://www.infoq.com/cn/news/2011/03/xxb-maven-5-integration-test
Maven实战(五)——自己主动化Web应用集成測试的更多相关文章
- Maven实现Web应用集成測试自己主动化 -- 部署自己主动化(WebTest Maven Plugin)
上篇:Maven实现Web应用集成測试自己主动化 -- 測试自己主动化(WebTest Maven Plugin) 之前介绍了怎样在maven中使用webtest插件实现web的集成測试,这里有个遗留 ...
- Maven实现Web应用集成測试自己主动化 -- 測试自己主动化(WebTest Maven Plugin)
近期在appfuse看到使用webtest-maven-plugin实现Web应用的集成測试,研究了下.感觉很不错.对于Web应用自己主动构建很有帮助,在性能測试之前能够保证Web应用的基本功能工作正 ...
- Python实战之自己主动化评论
Python实战之自己主动化评论 玩csdn博客一个多月了,渐渐发现了一些有意思的事,常常会有人用相同的评论到处刷.不知道是为了加没什么用的积分,还是纯粹为了表达楼主好人.那么问题来了,这种无聊的事情 ...
- Maven实战五
转载:http://www.iteye.com/topic/1123232 我们项目中用到的jar包可以通过依赖的方式引入,构建项目的时候从Maven仓库下载即可. 1. 依赖配置 依赖可以声明 ...
- Spring(五)Spring与Web环境集成
MVC 是 Model.View 和 Controller 的缩写,分别代表 Web 应用程序中的 3 种职责. 模型:用于存储数据以及处理用户请求的业务逻辑. 视图:向控制器提交数据,显示模型中的数 ...
- PAAS平台的web应用性能測试与分析
引言 为什么我会写这一篇博客,由于近期非常多京东云擎jae的用户反应一个问题就是他们部署在jae上面的应用訪问非常慢,有极少数应用甚至常常出现504超时现象.当然大家首先想到的是jae性能太差,这也是 ...
- Maven项目中mvn clean后找不到測试类问题
在Maven项目中进行单元測试,但mvn clean后又一次mvn install项目,再次进行单元測试.会有下面的错误. <span style="font-family:KaiTi ...
- 屏幕測试亮点,新买了一个显示器,使用web简单的測试下了亮点
1,购买了一个新的显示器 趁着双11的时候价格廉价.入手了一个显示器. http://serve.netsh.org/pub/dead_pixel.bin 滚动下就能够换颜色了.把chrome最大化, ...
- 带有机器人框架的.NET自己主动化測试
Clayton Neal在软件測试和质量保证方面有超过13年的经验,当中有八年的Windows, web,和移动应用程序的測试自己主动化经验.他在測试领域的全部等级都工作过.近期他在Bloomberg ...
随机推荐
- keytool常用操作
keytool 秘钥需要存储在秘钥库中,秘钥库可以理解为一个存储了一个或多个秘钥的文件.一个秘钥库可以存储多个密钥对,每个秘钥对你都需要给他们取一个名字. D:\software\Java\jdk1. ...
- head---显示文件的开头的内容
head命令用于显示文件的开头的内容.在默认情况下,head命令显示文件的头10行内容. 语法 head(选项)(参数) 选项 -n<数字>:指定显示头部内容的行数: -c<字符数& ...
- 9 hbase源码系列(九)StoreFile存储格式
hbase源码系列(九)StoreFile存储格式 从这一章开始要讲Region Server这块的了,但是在讲Region Server这块之前得讲一下StoreFile,否则后面的不好讲下去 ...
- 【cocos2d-x 3.7 飞机大战】 决战南海I (四) 敌机管理
敌方飞机应该不定时的出现,有自己的生命周期.运动轨迹.这个类用来管理敌机的产生.移动.爆炸.销毁等. 敌机管理类主要函数例如以下 //绑定控制器(更新分数) void bindController(C ...
- 基于Linux的智能家居的设计(2)
1 系统整体设计方案 智能家居系统的是一个实时查询家庭的温湿度.照明控制.自己主动控制的设定.集家庭娱乐.智能安防为一体,大量数据快处理.可靠的系统,因此在硬件和软件上都有非常大的要求,因此在这里进 ...
- JS控制光标定位,定位到文本的某个位置
这是一个数字密码,要能够智能的跳转到文本的某个位置,就需要通过JS来控制跳转! 1.onkeyup监听 <input class="put" id="number- ...
- CSS响应式布局到底是什么?
响应式布局是最近几年在前端开发中非常火热的词,它是相对于固定像素大小的网页而言的,那么CSS响应式布局到底是什么?顾名思义,响应式布局就是网页能够响应各种各样不同分辨率大小的设备,能够将网页很好的呈献 ...
- 2015北京网络赛 J Scores bitset+分块
2015北京网络赛 J Scores 题意:50000组5维数据,50000个询问,问有多少组每一维都不大于询问的数据 思路:赛时没有思路,后来看解题报告也因为智商太低看了半天看不懂.bitset之前 ...
- 程序发布出现: 服务器无法处理请求--->无法生成临时类(result = 1)。 错误CS2001:未能找到源文件“C:\ Windows \ TEMP \ lph54vwf.0.cs”
服务器上发布的web服务程序出错: 服务器无法处理请求--->无法生成临时类(result = 1).错误CS2001:未能找到源文件“C:\ Windows \ TEMP \ lph54vwf ...
- C# 从磁盘中读取文件
读取txt文件 ------读取的数据比较小的时候: 如果你要读取的文件内容不是很多,可以使用 File.ReadAllText(filePath) 或指定编码方式 File.ReadAllText( ...