开山篇--Java接口自动化测试选型与基础搭建

最近我司事业部的业务中台开发完毕,由于中台业务的特殊性,并没有对应的页面操作等,所以我们需要做
一个线上的可自动化部署的接口自动化测试平台,但是搜遍了全网的博客资料等,发现居然没有完整的自动
化的系列文章,找到的几十篇博客更是把如今的博客生态圈的抄袭展现的淋漓尽致,很多文章的内容是完全
一样的,而且最让人气愤的是,很多搭建的细节都没有描述,或者描述的并不是正确的,居然没有人进行验
证后在发,后来基于认识的某大厂的资深工程师给的经验和方案,慢慢摸索,踩了无数坑终于完成了我司的
接口自动化测试平台,现整理成系列给后来人使用

自动化测试的目标

首先,我们搭建之前必须要做的两件事:分析自动化测试平台需要完成的目标或者能实现的功能,以及基于我司业务的自动化测试的技术选型和工具选型,我们先来看第一点,自动化测试平台要完成的目标,决定这一点更重要的是根据我们需要测试的工程和项目是什么类别,业务方向,如何测试,以及测试目标等来决定

项目类型

我司项目类型为业务中台,即开放的业务Api平台,我司的中台架构采用CloudAlibaba系列重构,内部产品线使用RPC接口,Resful接口仅开放OpenApi使用,所以测试需要完全依赖于接口覆盖测试

业务方向(业务架构)

我司主要业务方向为电商与数字商业化,所以业务中台整体架构为三层服务,一级服务为各个基础能力中心,如注册中心,Redis开放能力中心,Mongo存储能力中心,外部服务中心,以及各个中间件、短信等基础能力中心,二级服务为依据我司数十个产品线业务功能模块能力整合拆分出来的业务中心,每个中心仅完成独立能力,如店铺相关能力中心,价格控制能力中心等,三级服务为完整的部分业务能力,按照完整的功能流程独立拆分,例如活动、促销、秒杀等相关的促销域,短信、EMAIL、商城客服聊天IM等相关的消息域等(仅对外开放三级业务域服务)

如何测试

由于我司项目的特殊性,所以在制定测试方式上,分为三类测试,即分为接口覆盖测试子流程闭环测试主分支业务流程覆盖测试,首先我们看第一类接口覆盖测试,此测试需要把我司对外的四百多个三级业务服务全部进行单元测试覆盖,并且完整测试通过,第二类子流程闭环测试,简单理解为每个域独立的业务串联测试,例如市场域的完整闭环流程可能会有多个,例如其中一个流程:申请开店-->审核开店(Y/N)-->设置店铺风格-->设置装修模版-->申请商品(创建商品)-->设置价格-->设置快递模版-->上架商品-->下架商品,至此一个简单的部分流程闭环完成,为什么说是简单的闭环流程呢?我想细心的可能发现,此流程都是涉及市场域相关的接口,并且按照流程顺序执行的,但是很多与之相关的操作并不存在,例如,用户注册、登录、实名认证、账户设置等前置流程没有涉及,且中间流程还有设置促销活动、订单、支付、配送、仓储、物流、结算等诸多流程没有涉及,所以仅为简单闭环流程--即本域业务范围内从无到有再到无的过程,而第三类测试即属于按照公司业务线发展,将中间所有的主流程全部涉及,覆盖面更广,数据要求更严格

测试目标

第一类接口测试我们的目标是接口全覆盖,代码覆盖率达到90%,并且测试目标为可持续多次运行,且测试通过,第二类测试要求可以循环测试多轮,且测试通过,第三类测试要求可动态循环测试,并且要求每一个流程的数据与理想数据相符,且测试通过

技术选型与测试相关工具

有了前面的条件后,我们就可以考虑技术选型和工具相关的准备工作了,毕竟工欲善其事,必先利其器嘛,我们先把能想到的准备好了,才能防止未知的问题,首先我们来看看技术选型,测试工程肯定是需要远程调用接口服务的,而常见的接口一般是Http和RPC两种,我们产品线内部使用则是直接选择RPC调度,所以Dubbo是必不可少的,而项目工程可能会需要独立运行的能力,而SpringBoot也是不错的选择,(至于Http接口,这里可以默认选择使用HttpClient框架进行请求工具类封装,也可以选择使用OkHttp3+Retfit2进行快速简单的Http请求操作)。而我们需要测试一般可选的市场主流的测试框架并不多,常见的如Junit、Nunit、TestNg、Mock等,而Mock用于模拟用户操作,并不触发真实操作,一般情况下用于接口开发的单元测试使用,可以有效的查找问题,而我们当前测试需要依赖真实的远程服务,进行请求操作,与Mock背道而驰,且我司在项目开发的过程中,已经使用Mock进行了单元测试,所以Mock被排除在外,JunitNunit属于类似的测试框架产物,由于是最早提出的测试剥离的框架,并且也是第一个进行完善测试的框架,所以一直到现在也是最常用的测试框架之一,但是JUnit有以下几个约束至今依然存在:

  • 它们的名称必须以 test 开始,如果不是test开头将会启动异常
  • 它们不返回任何值,junit测试过程中所有的测试方法必须是void,否则测试启动异常
  • 它们不能带任何参数,junit直到最新的版本中依然不支持动态测试传递参数,即方法必须无参,虽然发展到现在有各种设计模式和编程技巧可以让我们尽量避免这个约束的问题,比如使用全局变量,并且在测试启动的时候注入有参构造,解决传递参数的问题等,但是灵活度和实用性很差,测试工作也会变得局限性很大,且复杂度会很高

而TestNg比起Junit更年轻,且直到现在依然在保持着更新状态,TestNg从jdk1.5开始,就开始改变测试的方式和细节,完全拥抱java的新特性,如静态、注解等,TestNg提供了更多的生命周期和一堆默认组件,甚至于提供了大量的注解,可以满足常见的主流测试,主流IDE来说,TestNg也有对应的插件可以辅助测试,并且TestNg还有扩展机制,可以支持企业级复杂测试需求的定制化,由此可见,TestNg相比较于其他几个框架来说会更加合适一些,思考完这些,我们可以着手考虑开始快速搭建工程了

项目搭建

首先打开IDEA,使用Spring插件--Spring Assistant快速创建一个Springboot工程,这里我们默认选择SpringBoot2.1.9版本,下面需要选择的start启动类,我们默认勾选web启动类即可(其实这里我们不需要任何启动类,因为工程并不需要启动,也不需要成为web工程),然后等待工程创建完毕即可

strat.png

创建.png

web.png

选择完毕以后,等待工程创建完毕,这里我们将这三个文件进行删除:


删除三个文件.png

这个时候,我们打开pom.xml文件可以看到,当前工程中仅仅引入了spring-boot-web相关的jar以及test相关的jar,但是我们查看maven依赖可以看到,test中使用的jar是junit系列,所以我们需要重新添加testNg依赖,且为了简化开发,我们这里也依赖lombok,坐标如下:

<!--引入testNg-->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>6.10</version>
            <scope>test</scope>
        </dependency>

        <!--引入lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.10</version>
            <scope>provided</scope>
        </dependency>

至此,testNg基本集成已经完成,我们开始第一个Test类的编写吧!由于我们的maven依赖作用域范围为test,即jar生效范围在src/test包下生效,但是由于我们当前工程就是为了测试而搭建的工程,这里建议删除test包或者完全不编写,而是修改范围使其在src/main下生效,并且我们将版本号进行统一管理,修改后的依赖如下:

<!-- 版本号管理 -->
<properties>
        <java.version>1.8</java.version>
        <testNg.version>6.10</testNg.version>
        <lombok.version>1.16.10</lombok.version>
    </properties>

.............
<!--引入testNg-->
        <dependency>
            <groupId>org.testng</groupId>
            <artifactId>testng</artifactId>
            <version>${testNg.version}</version>
        </dependency>

        <!--引入lombok-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>${lombok.version}</version>
            <scope>provided</scope>
        </dependency>

现在我们开始编写我们的第一个Test类,开启我们的TestNg学习之旅吧

推荐阅读更多精彩内容