AICon上海|与字节、阿里、腾讯等企业共同探索Agent 时代的落地应用 了解详情
写点什么

用 Spring 实现非端到端验收测试

  • 2013-12-30
  • 本文字数:3478 字

    阅读完需:约 11 分钟

验收测试让交付团队超越了基本的持续集成,即验证应用程序是否为用户提供了有价值的功能。不过对于刚开始尝试部署流水线的团队来说,想要自动化验收测试,需要跨过三大门槛。

一是实现和维护验收测试的技术门槛。理想情况下,验收测试最好可以模拟用户与应用程序的真实交互,因此如果有图形界面的话,验收测试理应通过这个界面和系统打交道。然而,直接通过 GUI 进行测试会遇到几个问题:界面变化速度很快、场景的准备相对复杂、拿到测试结果较难等。比如一个典型的 WEB 应用程序,如果通过 GUI 测试,那么一般需要解析 HTML 标签来填写参数,提交表单,最后再次通过解析来获取系统的返回值。如果测试代码中充斥着操作 HTML 的细节,测试的可读性就会大大下降,验收测试本身也更脆弱,在需求变更时反而会拖慢进度。

二是交付团队工作方式的变化。在传统团队中,需求分析、开发和测试是独立而又顺序的过程。就算能形成详细的需求文档,三方对同一段文字可能都有自己的理解。结果经常出现偏差,需求分析人员抱怨开发人员没有正确理解需求文档,开发人员抱怨需求文档不清晰、抱怨测试人员故意挑刺。敏捷实践和验收测试的出现缓解了这一问题,通过预先定义验收规格,减少文字上的误解,明确了开发工作的完成标准。不过这种思维方式的转变很难一蹴而就,需要交付团队及其利益关系人共同持续努力才能成功。

三是对组织的环境、配置管理及部署流程的挑战。当引入自动化验收测试后,对整个部署流水线的自动化程度会有更高要求。比如部署流水线应该能够自动将应用程序部署到待测试的环境中。如果应用程序依赖数据库,那么还应该能够部署数据库 schema。另外一些运行时配置也需要通过脚本完成设置。这当中除了脚本准备之外,组织的环境管理也是要能跟上的。一般情况下,稍微大一些的组织都是有专门的运维团队(而非交付团队)来管理硬件设备和其配置的。因此,这个问题一般也涉及多个团队来协作解决。

面对这三座大山和进度压力,新手团队可能会感慨“信息量略大”而止步不前。这时不妨考虑各个击破,三个问题中的工作方式转变涉及的利益干系人最多,难度也最大;环境管理问题虽然涉及不同团队,但一般还是技术部门内的问题,关起门来好商量;验收测试的实现 / 维护主要是技术问题,相对最简单。如果时间和资源确实有限,不妨考虑牺牲一部分验收测试的有效性,采用简单的非端到端验收测试,在自动化部署流程方面也可以做一些折中,集中力量转变工作方式。当整个工作已经进入节奏,再去改进某个具体环节时就顺利很多了。团队只要愿意迈出一小步,也能获得很大的价值。

过渡方案:相对简单的非端到端验收测试

如果团队的技术积累还不足,又没有足够的资源,不妨考虑简单一些的验收测试策略作为过渡方案。非端到端的验收测试是指直接调用应用程序内部的逻辑结构来驱动测试。由于测试代码和产品代码都使用同一种语言编写,可以省去比较繁琐的数据格式解析。而在准备测试数据和场景时,直接调用内部逻辑块一般也更方便。以典型的使用 SpringFramework 的 Java WEB 应用程序为例,团队可以采用和集成测试类似的基础架构来编写非端到端的验收测试。

这里所说的集成测试的目的是验证应用程序与外部服务的连接能否正常工作。这与应用程序实现的具体功能关系不大,因此一般只加载必需的 ApplicationContext。

图表 1 集成测试

非端到端的验收测试可以采用和集成测试一样的测试基础架构,这样你就可以使用熟悉的测试库了,不同的是需要加载整个 ApplicationContext 以尽可能模拟应用程序被部署后的情况。

图表 2 加载整个上下文

由于可以访问整个 ApplicationContext 中的任一对象,我们可以通过访问应用程序的内部组件来执行测试,比如应用层的某个 Service。但需要注意的是,选取的组件离 UI 层越远,其模拟真实用户交互的有效性就越差,而且受内部实现变更的影响越大。如果应用程序使用 spring-webmvc 的 3.2 以上版本,推荐使用它的 mvc 测试库。spring-test-mvc 提供了类似 http 请求的 DSL,此时虽然测试还是基于 ApplicationContext,但并不直接访问内部组件了。这个方案对于新手团队比较友善,但请注意,这仅仅是个过渡方案,因为:

  • 非端到端测试无法提供全面的回归测试,尤其是 UI 操作。在好几个项目中,我们发现仅采用非端到端测试覆盖的功能,团队不得不保留手工回归测试。如果 UI 上包含了大量复杂的控制逻辑甚至有业务逻辑泄漏到 UI 组件中,这会稀释验收测试带来的收益。
  • 由于测试加载的 ApplicationContext 和 Web 容器加载的 ApplicationContext 存在差异,非端到端测试可能会漏掉一些问题。比如在非端到端测试中一次性加载了 booking-servlet.xml 和 root.xml,使他们成为了一个整体的上下文,而实际上在 Web 容器中并不完全是这样,root.xml 中的 bean 并不能访问和控制 booking-servlet.xml 中的 bean。一个常见问题就是如果在 booking-servlet.xml 中需要使用占位符,而恰巧我们已经在 root.xml 中有一个现成的 context:placeholder/ ,看起来水到渠成,而且在测试中也没有问题,但实际部署到 web 容器时,就会加载失败。
  • 非端到端的验收测试不能作为任务完成的最终标准。因为还有 UI 部分还没有完成。当这类验收测试通过时,我把这个任务称作“可以进入 UI 调试的”。

因此,如果团队有足够的技能和资源时还是应该直接使用端到端的验收测试,尤其当应用程序提供 API(比如 WebService)或是采用更易于解析的数据格式与客户端交互时。比如如果应用程序提供了基于 JSON 的 API,完全可以使用 http-client 来驱动测试。

实现非端到端的验收测试

来看看第一个验收测试,这个案例来自于著名的 dddsample ,为了让验收测试能够看上去高端大气上档次,我们将使用 Cucumber 来组织验收测试。验收场景描述的是业务员如何登记航运货件并解释了登记完成后货件的各项状态。

图表 3 第一个用户故事及其验收场景

Cucumber 提供了一系列的 Annotation 来帮助我们验收场景文本与测试代码粘连在一起。

图表 4 实现验收测试 -1

图表 5 实现验收测试 -2

接下来,当运行测试时,你就可以得到一份漂亮的 html 报告

图表 6 测试运行入口

维护非端到端的验收测试

当团队开始编写验收测试之后,一般没过多久就会发现验收测试的开发进度越来越慢,而且有时遇到测试失败,但其实应用程序并没有缺陷的情况。验收测试对代码质量的要求也很高,相比单元测试,为了要达到测试所需的起始状态,验收测试的准备工作要更复杂。而且由于需要解析应用程序返回的数据,验收测试的断言也会更加琐碎。因此,团队最好尽早开始重构验收测试,下面的建议或许有用处:

  • 建立最小测试数据集并且尽可能隔离测试的数据。有时团队会发现两组测试由于依赖同一批数据而产生冲突,单独执行任一组测试都能通过,但一起执行就会失败。比如在示例代码中,对于不同的货件处理事件登记场景,验收测试都会注册一个新的货件。
  • 隐藏断言细节。这样可以减少重复代码,并提升测试的可读性。把琐碎的解析逻辑隐藏在领域语言编写的方法中。

例如:如果多个测试用例都会对货件的运输状态进行断言,可以把解析细节提取出来,这样可以去除重复代码,并且减少语法噪声。

图表 7 抽取断言

  • 尽可能使用已实现的功能来实现测试场景的准备。有一些步骤可能是多个测试用例都需要来准备数据的,可以把此类步骤抽取出来。这样也可以减少重复的代码,当应用程序随着需求变化时,验收测试会有更强的适应性,而且抽取出来的方法由于隐藏了技术细节,使用起来更简练。直接使用数据脚本的方案看起来很诱人,但一旦内部结构改变,数据脚本也得跟着改。

图表 8 抽取公共步骤

验收测试对实践部署流水线的团队有着重要意义,也是很大的挑战。希望大家都能找到合适自己的方法。最后介绍几个有用的测试库。

  • Moco ,当有外部系统集成需求时,集成测试和验收测试的一大利器。在示例代码中你可以找到一处例子。
  • GreenMail ,如果应用程序需要发送邮件的话,它可以提供一臂之力。不过在部署流水线上的端到端验收测试中,由于一般应用程序和测试并不运行在同一台机器上,很难对邮件进行直接的断言。这时一种方案是修改应用程序的架构,把发送邮件的实现分离到一个专用的应用中去并使用消息队列集成。那么在验收测试中,我们就可以通过监听对应的消息队列来断言了。
  • Awaitility ,在需要对异步处理进行断言时有所帮助。

作者简介

周宇刚是一位乐于磨练技艺的开发者。他的研究和兴趣包括 IT 架构、领域驱动设计和敏捷实践。


感谢崔康对本文的审校。

给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。

2013-12-30 10:323240

评论

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

百度信息流和搜索业务中的KV存储实践

百度Geek说

后端 搜索

Python代码阅读(第29篇):使用初始化种子和迭代函数生成列表

Felix

Python 编程 Code Programing 阅读代码

华为云顾炯炯:云原生应用传送网络AND的实现架构与核心技术分享

华为云开发者联盟

网络 华为云 应用传送网络 ADN 东数西算

iPhone13全线机型上线WeTest云手机平台

WeTest

「可视化助力」,医疗进步无限可能

ThingJS数字孪生引擎

大前端 物联网 可视化

低代码平台的功能及其用处

低代码小观

程序员 低代码 开发工具 低代码开发平台 无代码

两个剪辑透明化融合视频特效处理

老猿Python

Python 音视频 视频剪辑 视频特效 引航计划

百度飞桨PaddleRobotics新升级!一套强化学习算法解决四足机器人多地形行走难题

科技热闻

AUTOSAR诞生的背景及其目的

SOA开发者

共生、互生、再生——英特尔与合作伙伴携手共建未来城市数字新基建

科技新消息

恒源云(GpuShare)_新功能制霸,信息量有点大

恒源云

Alibaba内部的10w字Java高频面试手册遭人恶意泄露

Java 面试 程序人生 编程语言 金九银十

基于星环大数据云平台 TDC 的一站式数据湖解决方案

星环科技

大数据 云平台

MPU:鸿蒙轻内核的任务栈的溢出检察官

华为云开发者联盟

鸿蒙 内核 任务栈 MPU 内存保护单元

maven如何忽略指定的远程仓库

小江

maven nexus 迁移 java;

玩转手工测试之百度客户端产品手工测试提效实践

百度开发者中心

最佳实践 方法论 手工测试

Elasticsearch IK 分词扩展词典(qbit)

qbit

elastic 扩展词 分词

最新!Apache APISIX 通过中国信通院 “可信开源项目” 认证

API7.ai 技术团队

Apache 开源社区 api 网关 APISIX 信通院

软件对智能汽车的影响

SOA开发者

必须得会的一些汽车ECU研发基础 --ECU硬件概念2

SOA开发者

防火防盗防内卷!阿里的24W字Java面试复盘指南,在Github上已标星98K+

Java 架构 面试 程序人生 编程语言

卷王本卷

FunTester

内卷 FunTester

做等保测评找哪家公司好?怎么选择?

行云管家

网络安全 等级保护 等保测评

2021年9月数据库流行度排行解读:聊聊国产数据库可以从哪方面做到以用户为中心

墨天轮

数据库 TiDB oceanbase 国产数据库 达梦

2021 DEMO CHINA创新中国总决赛峰会闭幕,光子晶体斩获2021 DEMO GOD

创业邦

星环ArgoDB+英特尔第三代至强=分布式闪存数据库“蜕变”

星环科技

数据库

高并发场景下的会话服务数据读写设计思路(附具体实施方案)

融云 RongCloud

数据库 缓存 即时通讯 IM 低时延

搞一下CP AUTOSAR 入门 | 01 CP AUTOSAR Overview

SOA开发者

深入理解Netty-从偶现宕机看Netty流量控制

vivo互联网技术

Java、 框架 netty

OceanBase 源码解读(五):租户的一生

OceanBase 数据库

数据开发 oceanbase OceanBase 开源 OceanBase 社区版 OceanBase 数据库大赛

HUAWEI雄起!顶级网络工程师总结出了这份网络协议开源笔记

Java 架构 面试 程序人生 编程语言

用Spring实现非端到端验收测试_语言 & 开发_周宇刚_InfoQ精选文章