You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

140 lines
12 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 35 | 如何准备测试数据?
你好,我是茹炳晟,今天我和你分享的主题是:如何准备测试数据。
从今天开始,我们将一起进入测试数据准备这个新的系列了。我会用四篇文章,和你详细探讨软件测试过程中关于测试数据准备的话题。我会依次分享测试数据创建的基本方法、测试数据准备的痛点、自行开发的测试数据工具,以及目前业内最先进的统一测试数据平台。
你我都非常清楚测试数据的准备是软件测试过程中非常重要的一个环节无论是手工测试还是自动化测试无论是GUI测试还是API测试无论是功能测试还是性能测试都避不开测试数据准备的工作。
所以,如果你想要成长为一名优秀的测试工程师,那就非常有必要深入理解测试数据准备的方法,以及它们各自的优缺点、适用场景了。
今天,我们就先从测试数据准备的基本方法开始吧。
从创建测试数据的维度来看,测试数据准备方法主要可以分为四类:
* 基于GUI操作生成测试数据
* 通过API调用生成测试数据
* 通过数据库操作生成测试数据;
* 综合运用API和数据库的方式生成测试数据。
这时相信你已经回想起我曾在第15篇文章[《过不了的坎聊聊GUI自动化过程中的测试数据》](https://time.geekbang.org/column/article/12399)中从创建测试数据的维度和你分享过这些内容这次的分享只不过是多了“通过GUI调用生成测试数据”的方法。
其实我在第15篇文章的分享内容只是简单的介绍了GUI测试数据准备的方法并没有详细展开。事后你可能也感觉不太过瘾想知道一些更深入、更细节、更贴近业务场景的测试数据准备的知识。所以也就有了我今天的这次分享。
那么,接下来我们就赶紧开始吧,一起聊聊这四种测试数据准备的方法。
## 基于GUI操作生成测试数据
基于GUI操作生成测试数据是最原始的创建测试数据的方法。简单地说它就是采用E2E的方式来执行业务场景然后生成数据的方法。
比如你想要测试用户登录功能那么首先就要准备一个已经注册的用户为此你可以直接通过GUI界面来注册一个新用户然后用这个新创建的用户完成用户登录功能的测试。
这个方法的优点是简单直接,在技术上没有任何复杂性,而且所创建的数据完全来自于真实的业务流程,可以最大程度保证数据的正确性。但是,该方法的缺点也十分明显,主要体现在以下这四个方面:
1. **创建测试数据的效率非常低**。一是因为每次执行GUI业务操作都只能创建一条数据二是因为基于GUI操作的执行过程比较耗时。
2. **基于GUI的测试数据创建方法不适合封装成测试数据工具**。由于测试数据的创建是通过GUI操作实现的所以把这种数据创建方法封装成测试数据准备工具的过程其实就是在开发GUI自动化测试用例。无论是从开发工作量还是从执行效率来讲把基于GUI操作的测试数据创建方法封装成测试数据准备工具都不是最佳的选择。
3. **测试数据成功创建的概率不会太高**。因为测试数据准备的成功率受限于GUI自动化执行的稳定性而且任何界面的变更都有可能引发测试数据创建的失败。
4. **会引入不必要的测试依赖**。比如你的被测对象是用户登录功能通过GUI页面操作准备这个已经注册的用户就首先要保证用户注册功能没有问题而这显然是不合理的。
鉴于以上四方面的原因在实际的测试过程中我们很少直接使用基于GUI的操作生成测试数据。只有在万不得已的情况下比如没有其他更好的方式可以创建正确可靠的测试数据时我们才会使用这个方法。
而且这里我需要说明的是基于GUI操作生成测试数据的方法一般只用于手工测试因为自动化测试中使用这种数据准备方法基本相当于要开发一个完整的GUI自动化测试用例代价太大。
那我为什么还要介绍这个方法呢其实这个方法更重要的应用场景是帮助我们找到创建一个测试数据的过程中后端调用了哪些API以及修改了哪些数据库的业务表是“通过API调用生成测试数据”以及“通过数据库操作生成测试数据”这两种方法的基础。
## 通过API调用生成测试数据
通过API调用生成测试数据是目前主流的测试数据生成方法。其实当我们通过操作GUI界面生成测试数据时实际的业务操作往往是由后端的API调用完成的。所以我们完全可以通过直接调用后端API生成测试数据。
还是以用户登录功能的测试为例我们通过GUI界面注册新用户时实际上就是调用了createUser这个API。既然知道了具体要调用哪个API那么我们就可以跳过在GUI界面的操作直接调用createUser生成“已经注册的用户”这个测试数据了。
**为了规避在创建测试数据时过于在乎实现细节的问题在实际工程实践中我们往往会把调用API生成测试数据的过程封装成测试数据准备函数**。那问题是我怎么才能知道前端新用户注册这个操作到底调用了哪些后端API呢这里我推荐三种方式
1. 直接询问开发人员,这是最直接的方法;
2. 如果你有一定的代码基础,可以直接阅读源代码,这个方法也可以作为直接询问方法的补充;
3. 在一个你可以独占的环境上执行GUI操作创建测试数据与此同时监控服务器端的调用日志分析这个过程到底调用了哪些API。
通过API调用生成测试数据的方法优点主要体现在以下几个方面
* 可以保证创建的测试数据的准确性原因是使用了和GUI操作同样的API调用
* 测试数据准备的执行效率更高因为该方法跳过了耗时的GUI操作
* 把创建测试数据的API调用过程封装成测试数据函数更方便因为这个调用过程的代码逻辑非常清晰
* 测试数据的创建可以完全依赖于API调用当创建测试数据的内部逻辑有变更时由于此时API内部的实现逻辑也会由开发人员同步更新所以我们依旧可以通过调用API来得到逻辑变更后的测试数据而这个过程对使用来说是完全透明的。
但是,该方法也不是完美无瑕的,其缺点主要表现在:
1. 并不是所有的测试数据创建都有对应的API支持。也就是说并不是所有的数据都可以通过API调用的方式创建有些操作还是必须依赖于数据库的CRUD操作。那么这时我们就不得不在测试数据准备函数中加入数据库的CRUD操作生成测试数据了。
2. 有时创建一条业务线上的测试数据往往需要按一定的顺序依次调用多个API并且会在多个API调用之间传递数据这也无形中增加了测试数据准备函数的复杂性。
3. 虽然相比于GUI操作方式基于API调用的方式在执行速度上已经得到了大幅提升并且还可以很方便地实现并发执行比如使用JMeter或者Locust但是对于需要批量创建海量数据的场景还是会力不从心。
因此业界往往还会通过数据库的CRUD操作生成测试数据。
## 通过数据库操作生成测试数据
通过数据库操作生成测试数据,也是目前主流的测试数据生成方法。这个方法的实现原理很简单,就是直接通过数据库操作,将测试数据插入到被测系统的后台数据库中。
**常见的做法是将创建数据需要用到的SQL语句封装成一个个的测试数据准备函数当我们需要创建数据时直接调用这些封装好的函数即可。**
还是以用户登录功能测试为例当我们通过GUI界面注册新用户时实际上是在后端调用了createUser这个API而这个API的内部实现逻辑是将用户的详细信息插入到了userTable和userRoleTable这两张业务表中。
那么此时我们就可以直接在userTable和userRoleTable这两张业务表中插入数据然后完成这个新用户的注册工作。
**这样做的前提是你需要知道前端用户通过GUI操作注册新用户时到底修改了哪些数据库的业务表**。这里,我也推荐三种方式:
1. 直接向开发人员索要使用到的SQL语句
2. 直接阅读产品源代码;
3. 在一个你可以独占的环境上执行GUI操作产生测试数据与此同时监控独占环境的数据库端业务表的变化找到哪些业务表发生了变化。
通过数据库操作生成测试数据的方法,主要优点是测试数据的生成效率非常高,可以在较短的时间内创建大批量的测试数据。
当然,这个方法的缺点也非常明显,主要体现在以下几个方面:
* 很多时候,一个前端操作引发的数据创建,往往会修改很多张表,因此封装的数据准备函数的维护成本要高得多;
* 容易出现数据不完整的情况,比如一个业务操作,实际上在一张主表和一张附表中插入了记录,但是基于数据库操作的数据创建可能只在主表中插入了记录,这种错误一般都会比较隐蔽,往往只在一些特定的操作下才会发生异常;
* 当业务逻辑发生变化时即SQL语句有变化时需要维护和更新已经封装的数据准备函数。
## 综合运用API和数据库的方式生成测试数据
目前在实际的工程实践中很少使用单一的方法生成测试数据基本都是采用API和数据库相结合的方式。**最典型的应用场景是先通过API调用生成基础的测试数据然后使用数据库的CRUD操作生成符合特殊测试需求的数据**。所以你经常会看到很多的数据准备函数中既有API操作又有数据库操作。
我以创建用户为例和你分享一下如何综合运用API和数据库两种方式创建测试数据吧。
假设我们需要封装一个创建用户的函数这个函数需要对外暴露“用户国家”和“支付方式”这两个参数。由于实际创建用户是通过后台createUser API完成的但是这个API并不支持指定“用户国家”和“支付方式”所以我们就需要自己封装一个创建用户的函数。
自己封装用户创建函数的方法,你可以通过下面这个思路实现:
* 首先调用createUser API完成基本用户的创建
* 然后调用paymentMethod API实现用户对于不同支付方式的绑定其中paymentMethod API使用的userID就是上一步中createUser API产生的用户ID
* 最后通过数据库的SQL语句更新“用户国家”。
在这个例子中createUser API和paymentMethod API只是为了说明如何综合运用API的顺序调用而其具体参数并不是我要阐述的关键内容所以我并没有和你详细说明这两个API的参数、实现方式等问题。另外我在最后一步综合运用了数据库的CRUD操作完成了创建测试数据的全部工作。
这,就是一个封装测试数据准备函数的典型例子了。
## 总结
今天,我从测试数据创建的角度,和你分享了准备测试数据的四种方法。
其中基于GUI操作生成测试数据是最原始的方法但是效率很低而且会引入不必要的依赖通过API调用以及数据库操作的方式生成测试数据是目前主流的做法通过API调用的方式具有数据准确度高但是创建效率较低的特点而通过数据库的方式具有创建效率高但是维护复杂度也高的特点。
所以在实际项目中业界往往会综合采用API和数据库的方式生成测试数据即通过API调用生成基础数据然后使用数据库的CRUD操作进一步生成符合特殊测试需求的数据。
## 思考题
目前,我们需要创建的测试数据并不仅仅局限于数据库,很多时候还需要创建消息队列里面的数据。你在实际工作中遇到过这类测试数据吗?你又是如何处理的呢?
感谢你的收听,欢迎你给我留言。