RESTFul 服务测试自动化的艺术 - TODO 服务篇

2018 年 6 月 1 日 开源中国


作者:罗格林

链接:

https://my.oschina.net/greenlaw110/blog/1821431


老码农在上一篇博客 给出了如何从头开始创建一个 自带自动化测试工具的 RESTful 服务项目的例子. 今天我们在这个简单例子上做延伸, 把这个例子改写为一个简单的 TODO Task 应用. 该应用会提供以下服务端口:


  • GET /todos - 返回所有的 TODO 项

  • GET /todos/?q=? - 查询 TODO 项, 所有描述符合 q 参数的 TODO 项都会被返回

  • GET /todos/{id} - 返回指定 ID 的 TODO 项

  • POST /todos - 添加一条 TODO 项

  • DELETE /todos/{id} - 删除指定 ID 的 TODO 项


1. 创建项目


下面开始创建初始项目:



下面我们将项目用 Intellij IDEA 打开. (推荐使用 IDEA 开发 Act 应用, 社区版足够使用了)



2. 加入数据库访问插件依赖


可以删除掉项目创建的 Service.java 文件. 然后在 pom.xml 中加入一下依赖:



act-eclipselink 使用 EclipseLink 提供数据库访问服务. 也可以换为 act-hibernate, 对我们这个 todo-service 的开发没有任何变化.


3. 加入 Todo 服务相关类


现在可以在项目中创建我们的 Model 类 - Todo:



注意, 这里实现了 SimpleBean 框架会自动为 Todo 创建 Getter 和 Setter 方法. 在 Todo 之外的地方调用 todo.desc = "abc" 会被自动更换为 todo.setDesc("abc"), 而 String s = todo.desc 则会被自动更换为 String s = todo.getDesc().


下面创建 Todo 的服务类 TodoService:



4. 启动并试用服务


好了, 开发工作搞定. 现在运行起来试试. 有两种方法运行程序.


  1. 在 IDE 里面运行:



  1. 通过 mvn 命令在控制台运行:



选择任何一种方式, 把应用跑起来之后, 我们用 httpie 来试试我们的 Todo 服务:


4.1 创建一个 todo 项



4.2 获取 todo 列表



4.3 获取 id 为 1 的 todo 项



4.4 删除 id 为 1 的 todo 项, 并验证



到此基本上我们的实现部分就完成了, 同时也手工做了测试. 看看代码统计:




所有 Java 代码加起来也就 58 行, 虽说是一个非常粗糙的 Todo 服务, 也算是麻雀虽小五脏俱全了.


5. 自动测试的实现


下面开始进入肉戏了. 我们刚刚使用了 httpie 对服务进行了测试, 貌似也很简单, 可这毕竟需要人工介入啊. 没听葛先生说过二十一世纪人工最贵吗? 怎么能把这么贵的人工浪费在重复性的工作上面. 更重要的问题是人工在这种重复性劳作上远远不如机器可靠, 如果没有自动化测试的保障, 即便是大牛也不敢随便对代码动刀子搞搞重构之类的高级手术.


那自动化测试怎么搞, 这是一个问题. 老码农也思考了很多年. 最初的想法是复制 Spring 的招数, 搞一个 ActRunner之类的东西让开发人员能在 JUnit 框架下跑对 Act 应用的测试. 可当老码农看到 3.4.5. Meta-Annotation Support for Testing 一节的时候已经被吓傻了, 仅仅是为了支持测试可能会用到的注解就已经是这番模样了:



这完全和 Act 的核心理念背道而驰啊. 欲破珍珑棋局, 必须跳出棋盘, 自动测试也不是一定要在 JUnit 框架下进行. 多年寻寻觅觅找不到满意的方案, 这思路一开, act-e2e 插件便横空出世.


5.1 act-e2e 简介


act-e2e 是老码农为 Act 应用开发提供的自动化测试插件, 其设计目的主要有一下几点:


  1. 提供端到端测试支持, 换句话说, 测试通过 HTTP 协议向应用发送请求, 并接受应用传回的 HTTP 响应, 并验证响应的内容

  2. 测试脚本应该易于编写. 用户只需要定义每次交互的请求数据以及响应数据的验证方式, 完全无需考虑应用内部实现

  3. 测试环境治理. 这包括:

  • 运行测试场景之前对数据库清除

  • 运行测试场景之前加载指定数据文件到数据库中

  • 数据文件 (Fixture) 通过 YAML 格式定义, 包括数据项之间的关联关系

  • 测试场景的依赖管理, 某些测试场景可能被其他场景依赖, 比如用户登录这个场景就可以被很多其他测试场景依赖. 而用户登录自身又可能依赖与用户注册场景.

  1. 其他工具, 比如共享的请求模板, 如果大部分请求都需要添加某些 HTTP 头, 可以定义请求模板, 并被其他请求引用.


5.2 Scenarios 文件


定义 Scenarios.yml 文件内容是使用 act-e2e 进行自动化测试的核心活动. 这个文件的结构如下:



在本文中我们不会详细罗列整个 Scenarios 文件的语法结构, 而是通过对 Todo 服务进行自动化测试来介绍 Scenarios 文件的用法.


5.3 为 Todo 服务实现自动测试


打开 src/main/resources/e2e/scenarios.yml 文件, 清除其中的内容, 添加针对 TODO 服务的测试脚本. Todo 服务足够简单, 一个场景足够涵盖基本测试, 我们首先加入场景声明:



5.3.1 第一个交互: 添加 Todo 项目


接下来加入第一个交互:



分解一下该交互的定义. 首先是请求:




请求的元素主要为:


  • method: HTTP 方法, 可以为 GET/POST/DELETE/PUT/PATCH/HEAD

  • url: 测试服务的 URL

  • params: 请求发送的参数

  • headers: 请求头. 这个部分在本文中不会使用


本例中响应的定义为:



这个定义的意思是, 这个响应应该是一个 {"result": ...} JSON 结构. 该定义来自 Todo 服务的下面的服务端口:




从代码看来, 返回的应该是一个整数类型的值. 但因为我们前面定义了整个控制器都是 @JsonView, 也就是任何返回都应该是合法的 JSON 结构. 对于无结构的值, 我们使用 result 来包裹返回值. 因此, 我们的响应定义中有 result: -exists: true 这样的验证.

加入第一个交互之后我们就可以试试 e2e 了, 打开浏览器, 导航到 localhost:5460/~/e2e, 会看到定义的测试以及运行情况:



5.3.2 查询新创建的记录



这个交互定义有个地方值得注意: url: /todos/${last:result}, 这个的意思是取上一个交互对象的 result 引用的值填充到 /todos/ 后面, 也就是说 url 最后会是 /todos/{id}, 而 {id} 是上次添加 Todo 项生成的 id.


对于 response 的定义则是检测是否 JSON 数据中的 desc 为 Task A.


回到浏览器, 按 F5 刷新:



5.3.3 获得 Todo 列表



这个交互定义中比较有趣的是响应的验证定义. 其含义是 json 数据是一个数组, 其中有一个元素, 第一个元素的 desc 为 Task A


刷新浏览器得到:



5.3.4 查询 Todo 列表



这个和前面的交互 [5.3.3 获得 Todo 列表] 非常接近, 唯一不同的地方是 GET 请求多了请求参数: q=A. 表示查询含有 A 字母的 Todo 项.


再次刷新浏览器:



Oops, 怎么最后的交互没有通过. 回到后台, 发现这样的错误:




这应该是希望返回数组有一个元素, 但实际返回数组没有元素. 仔细检查一下, 应该是在 A 前面加上 % 才行, 更改我们的 scenarios.yml 文件, 将 q: A 改成 q: %A, 之后再刷新浏览器:



貌似错误更加严重了, 原来 % 是 yaml 的保留字符, 需要用引号括起来, 即 q: %A 变为 q: '%A'. 最后终于全部搞定了:



5.4 在 CI 中集成 e2e 测试


我们上面的过程都使用了浏览器访问 /~/e2e 来完成测试. 这个对于开发调试 sceanrios.yml 测试脚步非常方便. 但是对于 CI 集成自动测试过程就不友好了. 不用担心, Act 的 maven 插件可以帮忙解决这个问题:



获得的结果是:




这里还需要一些改进, 方便 CI 工具更容易判断测试是否通过. 老码农会在以后的版本中持续改进对端到端自动测试的支持.


另外在操作过程中有可能出现一些异常现象, 需要重启动应用. 这个问题老码农已经提交 issue 报告了. 将会在以后的版本中修复.


本文讲述的项目代码在 gitee 上有完整版本, 有兴趣可以参考:


  • https://gitee.com/greenlaw110/todo-service/



参与「程序员专属信用卡调研

让我们打造最适合程序员的信用卡!


美食、购物、航旅…优惠折扣等着你哦~


扫码参与投票




推荐阅读

国产系统“强行”快于国外系统,网友:面对现实这么难?

C++ 协程的近况、设计与实现中的细节和决策

看似简单的 Windows 记事本,其实维护起来并不简单

联想回应“反对预装国产系统”消息:谣言,一直支持国产

吃透这套架构演化图,从零搭建 Web 网站也不难!

点击“阅读原文”查看更多精彩内容

登录查看更多
0

相关内容

RESTful是一种软件架构风格,设计风格而不是标准,只是提供了一组设计原则和约束条件。它主要用于客户端和服务器交互类的软件。基于这个风格设计的软件可以更简洁,更有层次,更易于实现缓存等机制。
【实用书】流数据处理,Streaming Data,219页pdf
专知会员服务
76+阅读 · 2020年4月24日
【资源】100+本免费数据科学书
专知会员服务
107+阅读 · 2020年3月17日
深度神经网络实时物联网图像处理,241页pdf
专知会员服务
76+阅读 · 2020年3月15日
【新书】Java企业微服务,Enterprise Java Microservices,272页pdf
【干货】大数据入门指南:Hadoop、Hive、Spark、 Storm等
专知会员服务
95+阅读 · 2019年12月4日
Keras作者François Chollet推荐的开源图像搜索引擎项目Sis
专知会员服务
29+阅读 · 2019年10月17日
微信小程序支持webP的WebAssembly方案
前端之巅
19+阅读 · 2019年8月14日
已删除
AI掘金志
7+阅读 · 2019年7月8日
一个牛逼的 Python 调试工具
机器学习算法与Python学习
15+阅读 · 2019年4月30日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
支持多标签页的Windows终端:Fluent 终端
Python程序员
7+阅读 · 2019年4月15日
如何编写完美的 Python 命令行程序?
CSDN
5+阅读 · 2019年1月19日
React Native 分包哪家强?看这文就够了!
程序人生
13+阅读 · 2019年1月16日
如何用GitLab本地私有化部署代码库?
Python程序员
9+阅读 · 2018年12月29日
The Evolved Transformer
Arxiv
5+阅读 · 2019年1月30日
Arxiv
12+阅读 · 2018年9月5日
Arxiv
3+阅读 · 2018年6月19日
VIP会员
相关VIP内容
相关资讯
微信小程序支持webP的WebAssembly方案
前端之巅
19+阅读 · 2019年8月14日
已删除
AI掘金志
7+阅读 · 2019年7月8日
一个牛逼的 Python 调试工具
机器学习算法与Python学习
15+阅读 · 2019年4月30日
使用 C# 和 Blazor 进行全栈开发
DotNet
6+阅读 · 2019年4月15日
支持多标签页的Windows终端:Fluent 终端
Python程序员
7+阅读 · 2019年4月15日
如何编写完美的 Python 命令行程序?
CSDN
5+阅读 · 2019年1月19日
React Native 分包哪家强?看这文就够了!
程序人生
13+阅读 · 2019年1月16日
如何用GitLab本地私有化部署代码库?
Python程序员
9+阅读 · 2018年12月29日
Top
微信扫码咨询专知VIP会员