生成式AI领域的最新成果都在这里!抢 QCon 展区门票 了解详情
写点什么

用 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:322827

评论

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

电商“变法”,AI维新

脑极体

AI

为什么单元测试不是持续交付的唯一答案

敏捷开发

项目管理 DevOps CI/CD 测试 单元测试 产品研发

C# 12 中新增的八大功能你都知道吗?

EquatorCoco

.net C语言 开发语言

揭开华为云ADN提高网络质量的秘密

华为云开发者联盟

开发 网络 华为云 华为云开发者联盟 华为云DTSE

无缝对接,提升企业办公与薪酬福利管理效率!

聚道云软件连接器

案例分享

数字化商品管理:革新鞋服零售模式,引领智能商业新时代

第七在线

跨境电商企业都在用的云手机是什么?

Ogcloud

云手机 海外云手机 云手机海外版 国外云手机 电商云手机

面试官:如何实现10亿数据判重?

王磊

Java 面试题

IPQ9574/Breaking the speed boundary: exploring the innovative technologies of WiFi 7

wallysSK

DevData Talks | 金融大咖说:金融企业如何持续提升研发效能

思码逸研发效能

思码逸企业版 4.0 特性之二:支持 DevOps 全工具链数据分析

思码逸研发效能

信息茧房的困境

老张

信息茧房 sora

区块链软件开发:创新、安全、智能的数字未来

区块链软件开发推广运营

dapp开发 区块链开发 链游开发 NFT开发 公链开发

思码逸企业版 4.0 特性之一:支持 DevOps 全工具链数据分析

思码逸研发效能

收藏!如何有效实施DevOps?

敏捷开发

项目管理 DevOps 运维 单元测试 #后端

下一代Edge AI的应用初探

这我可不懂

人工智能 AI

适合tiktok运营的云手机需要满足什么条件?

Ogcloud

云手机 海外云手机 tiktok云手机 Tik Tok

基于Java开发的工作流管理系统,快速开发平台

金陵老街

oracle和mysql语句有哪些异同点?

伤感汤姆布利柏

利用大数据和API优化电商决策:商品性能分析实践

Noah

玩转 Go Slices 切片泛型库

陈明勇

Go golang 后端 go slices

命名虚拟机及设置安装路径

小魏写代码

海外云手机在电商平台的用途

Ogcloud

云手机 海外云手机 云手机海外版 国外云手机 电商云手机

全彩LED显示屏选购指南

Dylan

产品 LED显示屏 全彩LED显示屏 led显示屏厂家

Go 1.22 slices 库的更新:高效拼接、零化处理和越界插入优化

陈明勇

Go golang 后端 Go 1.22

在script标签写export为什么会抛错|type module import ES5 ES6 预处理 指令序言 JavaScript JS

Geek_ee6d52

前端 JavaScrip

以太坊 Dencun 升级与潜在机会

TechubNews

Ethereum 区块链、 #Web3

NFTScan | 02.12~02.18 NFT 市场热点汇总

NFT Research

NFT NFT\ NFTScan

极速提升测试效率:揭秘Web自动化三大等待技巧

测吧(北京)科技有限公司

测试

一站式指南:ClkLog部署环境配置指南

ClkLog

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