您可以捐助,支持我们的公益事业。

1元 10元 50元





认证码:  验证码,看不清楚?请点击刷新验证码 必填



  求知 文章 文库 Lib 视频 iPerson 课程 认证 咨询 工具 讲座 Modeler   Code  
会员   
 
   
 
 
     
   
 订阅
  捐助
Moco 框架以及其在 Web 集成测试的应用
 
作者:沈锐 来源:IBM 发布于 2015-8-4
   次浏览      
 

集成测试介于单元测试和系统测试之间,起到“桥梁作用”。具体到 Web 集成测试,由于其自身的“特殊性”往往需要面对更大的挑战,更多的痛点,本文主要是在这个问题上的一些思考性文章,同时为大家推荐 – 2013 年 Oracle Java 大赛的获奖作品 Moco。

Moco 框架以及其在 Web 集成测试的应用

我们往往将软件测试可以分为单元测试、集成测试、系统测试和验收测试。而集成测试界于单元测试和系统测试之间,起到"桥梁作用",一般由开发小组采用白盒加黑盒的方式来测试,既验证"设计",又验证"需求"。 主要用来测试模块与模块之间的接口,同时还要测试一些主要业务功能。集成测试(也叫组装测试,联合测试)是单元测试的逻辑扩展。它最简单的形式是:把两个已经测试过的单元组合成一个组件,测试它们之间的接口。从这一层意义上讲,组件是指多个单元的集成聚合。在现实方案中,许多单元组合成组件,而这些组件又聚合为程序的更大部分。方法是测试片段的组合,并最终扩展成进程,将模块与其他组的模块一起测试。最后,将构成进程的所有模块一起测试。此外,如果程序由多个进程组成,应该成对测试它们,而不是同时测试所有集成测试进程。

Web 集成测试

在很多时候,我们的 Web 应用程序往往会成为项目的瓶颈,以至于影响整个项目的按时发布。那么我们不禁要问,为什么会出现这样的情况?是什么在阻碍着项目的进度?在我们深入探讨这个问题之前,让我们先回忆一下一个典型的 Web 项目开发所经历的过程,从而寻找出问题的根源。
从开发的流程上看,它与其他的产品开发没有本质的区别,无外乎立项、审核、开发、集成、测试、维护这些具体的过程。每个步骤参与的人员和行为也都大同小异,然而您会发现往往很多的 Web 项目总是在集成测试环节出现这样或者那样的问题?(当然集成测试符合普氏原理,其他的产品开发也会遇到这样棘手的问题,只是 Web 显得更加的明显和突出罢了)其实这和具体的 Web 项目没有多大的关系,有点绕?哦,这句话的意思就是,我们需要将思维跳出具体的项目本身,从整个产品的角度来看待问题,这样就很容易找到痛点。那么让我们换个角度来看这个问题:

客户–〉Web/客户端–〉系统基础软件

从上面的关系中我们可以看到,作为"食物链"顶端的 Web 项目往往起着一个"中间人"的角色,在它之下是系统软件(如操作系统本身或者其上的中间件),而在它之上往往直接面对客户。在软件开发的经典教程里,总是将这种处于中间衔接层的软件设计称为--鲁棒性。也就是说它需要的是某种颠覆性的 OUTPUT,将具体的需求转化为实际的可以操作的架构设计,这样的一个"中间人"往往在一个产品的生命周期中扮演者举足轻重的角色。

Web 集成测试的痛点

而 Web 项目区别于其他项目的本质原因就在于,它直接面对需求的提出者--客户,而这部分的需求变动也是最为活跃的。也就是因为这样,往往很多时候我们对于 web 的开发要求的就是,快速!但这样的观点仅仅限于在 UI 或者 Web 编程方面,对于与底层系统的集成往往素手无策?因为底层系统一般来说是公司产品的核心内容,也遵循着典型的产品开发模式,在需求变更方面也显得很谨慎而小心。面对突入其来的的需求变动,底层系统往往很难跟的上节奏,而且很多时候 Web 的开发和底层系统的开发是分开的,或者分属于不同的开发部门,即使是一个方法级别的调用,就会浪费掉大家很多的沟通成本,接口的变更或者是 API 的向下兼容这些都是翻来覆去争论的话题。由于大家所处的开发领域不同,工作的方式,方法的不同,甚至是编程语言的差别,这些问题最终会暴露在集成测试这里,从而影响整体项目的开发进度。

这里就有一个真实的案例。在 Web 开发中,我们遇到了大数据显示的问题,分页显示无疑是最合适,也最很容易想到的解决方案。但由于其他的因素,底层系统无法在既定的项目期限内给予 API 方面的支持,在经过深入的沟通和相互理解之后发现,这样的功能在系统层面这个角度来说,属于优先级较低的功能。而且在他们开来,客户往往更习惯于使用命令行查看结果,并没有提出这样的需求,当然这样的争论是没有意义的,大家看待问题的角度不同,我们也不能一概而论,毕竟还是还有一些客户并不属于"专业级"用户,或者由于其他的原因的限制,他们不得不选择使用浏览器查看执行结果,面对这样的情况,摆在 Web 开发人员面前的问题就是如何在既定的情况下修改已有的结构,从而支持数据分页并且保证足够的可扩展性,以保证在未来底层系统可能支持的情况下,将代码修改的成本降低到最小?

解决思路和方案

问题已经暴露出来,让我们畅想一下期望的开发模式是什么,可能更容易让我们审核目前的问题,并找到最佳的解决方案。让我们畅想一下,如果我们在 Web 开发阶段没有这么多的顾虑而专注于功能本身,或者说我们总是假定底层系统足够的强大,并支持所有可能的的需求变更,是不是就没有这样的问题了?那么是否真的有这样的一个框架开始关注于这些问题,从而将 Web 开发人员解放出来,使其更加关注于自身领域的的需求呢?换句话说我们需要一个"模拟"的底层系统,它返回所有我们希望的结果,从而让我们将所有的注意力放在 Web 这个层面,对,这就是今天要介绍的 Moco!

Moco 是什么

作者是这样描述 Moco 的:

Moco是一个简单搭建模拟服务器的程序库/工具,这个基于 Java 开发的开源项目已经在 Github 上获得了不少的关注。该项目的简介是这样描述自己的:Moco 是一个简单搭建 stub 的框架,主要用于测试和集成。这个框架的开发灵感来自 Mock 框架,如 Mockito 和 Playframework。
为什么要开发这个框架?

集成,尤其是基于 HTTP 协议的集成——web service、REST 等,在我们的项目开发中被广泛应用。以前,我们每次都要往 Jetty 或 Tomcat 等应用服务器上部署一个新的 WAR。大家都知道,开发部署一个 WAR 的过程是很枯燥的,即使在嵌入式服务器上也是如此。而且,每次我们做一点改动,整个 WAR 都要重新组装。

Moco 的出现,正是为了解决这些问题。开发团队只要根据自己的需要进行相应的配置,就会很方便得到一个模拟服务器。而且,由于 Moco 本身的灵活性,其用途已经不再局限于最初的集成测试,比如,Moco 可以用于移动开发,模拟尚未开发的服务;Moco 还可以用于前端开发,模拟一个完整的 Web 服务器,等等。

在 2013 年Duke's Choice Awards上,Moco 框架被提名为最具创新力的 Java 项目之一,在 Twitter 上得到了 Martin Fowler 的关注,详见《企业系统集成点测试策略》一文在 InfoQ 英文站

Moco 下的 Hello World

首先,您需要:

1.配置您的 Java 环境

下载 Java 程序,并设置好系统环境变量 (PATH, JAVA_HOME)

2.安装并配置 Gradle

具体可以参考http://www.gradle.org/

接下来,按照下面的步骤安装 Moco

1.获取 Moco 源文件

使用 git 命令,获取最新的代码

git clone https://github.com/dreamhead/moco.git

也可以直接下载编译好的 Jar 文件,目前是 0.9.1

编译源代码,生成 Jar 文件 (用以编译好的 Jar 文件的,可以忽略这个步骤) 在命令行执行如下的命令

cd <moco directory>
./gradlew build

2.编写配置文件,以简单的 Hello World 为例

[
{
"response" :
{
"text" : "Hello, Moco"
}
}
]

将文件以 json 的后缀存储,比如 foo.json

3.启动 Moco 服务

在命令行输入

java -jar moco-runner-<version>-standalone.jar start -p 12306 -c foo.json

注:-p 指定 Moco 服务端口 (目前仅指 Web 端口)

4.访问 Web 服务

打开浏览器,访问 http://localhost:12306

您应该可以立即看到久违了的"Hello World"

Moco 的复杂实例

实例一, 带参数的 HTTP 请求

有些时候我们希望能够在请求的同时,传递相应的参数。这时我们需要用到"queries"关键字

配置文件

{
"request" :
{
"uri" : "/foo",
"queries" :
{
"param" : "blah"
}
},
"response" :
{
"text" : "bar"
}
}

启动浏览器,并访问

http://localhost:12306/foo?parm=blash

实例二,基于正则表达的 URL 匹配

在很多对 URL 请求的测试中,我们希望对于多个相似的 URL,都返回相同的结果

配置文件

{
"request":
{
"uri":
{
"match": "/\\w*/foo"
}
},
"response":
{
"text": "bar"
}
}

启动浏览器

在地址栏输入多个地址(/foo 前带有任意字符, 比如 http://localhost:12306/xxx/foo)

实例三:跳转

页面的自动跳转也是经常在 Web 开发中遇到的问题之一

配置文件

{
"request" :
{
"uri" : "/redirect"
},
"redirectTo" : "http://www.github.com"
}

启动浏览器访问 http://localhost:12306/redirect

页面将会被自动导向到 http://www.github.com

实例四: 返回 JSON 对象

在 Web 开发中,对于 JSON 的操作是最典型的应用

配置文件

{
"request": {
"uri": "/json"
},
"response": {
"json": {
"foo" : "bar"
}
}
}

启动浏览器访问 http://localhost:12306/json

页面上会显示输出的 JSON 对象

Moco 高级用法

在 Moco 里您还可以发现一些好玩的,或者说高级用法,比如 Asynchronous、Template。具体用法还是参考 Moco 的文档,这里仅以 Asynchronous 为例。

编写配置文件

{
"request": {
"uri" : "/event"
},
"response": {
"text": "event"
},
"on": {
"complete": {
"async" : "true",
"post" : {
"url" : "http://another_site",
"content": "content"
}
}
}
}

那么对于/event 的访问,将会是异步。

也就是说数据并不会立即返回,而是要等到对 http://another_siter 访问结束后,才会将结果放到 Response 里。

Moco 的 API 用法

前面的这些用法在 Moco 里被称为"Standalone", 它强调的是 Moco 的简单性和可配置性,而 Moco 的 API 是它的另一个特色,它更加关注如何在测试用例里如何使用 Moco。

我们先看一个基于 Moco 的典型测试用例

import org.junit.Test;
import java.io.IOException;
import com.github.dreamhead.moco.HttpServer;
import org.apache.http.client.fluent.Content;
import org.apache.http.client.fluent.Request;
import com.github.dreamhead.moco.Runnable;

import static com.github.dreamhead.moco.Moco.*;
import static com.github.dreamhead.moco.Runner.*;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;

@Test
public void should_response_as_expected() throws Exception {
HttpServer server = httpserver(12306);
server.response("foo");

running(server, new Runnable() {
@Override
public void run() throws IOException {
Content content = Request.Get("http://localhost:12306").execute().returnContent();
assertThat(content.asString(), is("foo"));
}
});
}

上面的测试用例,描述了如何启动 Moco,以及调用相应的帮助方法来编写测试。

有时我们希望测试用例本身能够控制 Server 的启动和关闭,这里要用到@Before, @After 这些 Junit 里最常用的注释

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;

import static com.github.dreamhead.moco.Moco.httpserver;
import static com.github.dreamhead.moco.Runner.runner;
import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

public class MocoRunnerTest {
private Runner runner;

@Before
public void setup() {
HttpServer server = httpserver(12306);
server.response("foo");
runner = runner(server);
runner.start();
helper = new MocoTestHelper();
}

@After
public void tearDown() {
runner.stop();
}

@Test
public void should_response_as_expected() throws IOException {
Content content = Request.Get("http://localhost:12306").execute().returnContent();
assertThat(content.asString(), is("foo"));
}
}

Moco + Web 集成测试案例

了解了 Moco 的具体使用方法,我们来看一个真实的基于 Moco 的案例,从而理解为什么 Moco 对于 Web 开发人员来说是革命性的!

用例:

在 Web 上调用 Ajax 获取服务器端的版本(version)号,并根据返回的值显示不同的提示信息。

分析:

其实面对这样的需求,我们很容易看出这个用例本身,关注的是"显示不同的提示信息"这个功能,至于返回的 version 值,用户根本不必关心或者说这属于系统内部的逻辑。

我们先来看看以前的做法

安装并配置好 Web Server (Tomcat or Apache)

建立必要的 Web 工程文件,导入与项目相关的框架,比如 struts2

如果底层系统是 Java 本身,需要导入或者编译相关的 jar 文件,如果底层用其他的语言开发,就需要步骤 4

搭建底层开发环境或者在编译机器上编译 Lib 或者 so 文件,在确保能够运行的情况下(需要测试脚本)并导入到项目当中

发布 Web 应用并测试,如果底层 API 有变动或者方法调用错误,需要再次运行步骤 4。

编写并测试 Ajax 逻辑。

那么我们看看基于 Moco 的开发步骤会是什么样的:

编写配置文件, 这里要用到刚才说的同步方法

[
{
"env" : "remote",
"include": "foo.json",
},
{
"env" : "local",
"include": "bar.json",
}
]

启动 Moco 服务

java -jar moco-runner-<version>-standalone.jar start -p 12306 -g env.json -e remote

在很多时候,我们往往将时间浪费在步骤 3,4 中,即使已经有编译好的 Lib 或者 so,还是存在着测试的必要和风险。Web 的开发人员一方面要完成自己开发任务,另一方面还要扮演底层代码测试员角色。

编写 Web 应用,调用 ajax 请求

Moco 让开发人员更关注应用本身,而不必将时间和精力花费在 Lib 或者 so 的可用性上,而且没有复杂的 Web 容器配置,关注的就是切实的功能本身。

同时,它的 API 有利于 Web 开发者编写测试用例,将以前部门之间的无效沟通,建立在可度量的测试用例之上,从而提高了 Web 集成测试的可靠性,并有效地降低了集成测试的风险!

   
次浏览       
相关文章

微服务测试之单元测试
一篇图文带你了解白盒测试用例设计方法
全面的质量保障体系之回归测试策略
人工智能自动化测试探索
相关文档

自动化接口测试实践之路
jenkins持续集成测试
性能测试诊断分析与优化
性能测试实例
相关课程

持续集成测试最佳实践
自动化测试体系建设与最佳实践
测试架构的构建与应用实践
DevOps时代的测试技术与最佳实践
最新活动计划
LLM大模型应用与项目构建 12-26[特惠]
QT应用开发 11-21[线上]
C++高级编程 11-27[北京]
业务建模&领域驱动设计 11-15[北京]
用户研究与用户建模 11-21[北京]
SysML和EA进行系统设计建模 11-28[北京]

LoadRunner性能测试基础
软件测试结果分析和质量报告
面向对象软件测试技术研究
设计测试用例的四条原则
功能测试中故障模型的建立
性能测试综述
更多...   

性能测试方法与技术
测试过程与团队管理
LoadRunner进行性能测试
WEB应用的软件测试
手机软件测试
白盒测试方法与技术

某博彩行业 数据库自动化测试
IT服务商 Web安全测试
IT服务商 自动化测试框架
海航股份 单元测试、重构
测试需求分析与测试用例分析
互联网web测试方法与实践
基于Selenium的Web自动化测试
更多...