# apitest **Repository Path**: qinxie/apitest ## Basic Information - **Project Name**: apitest - **Description**: 一款完备且实用的接口自动化测试框架。支持REST, RPC, SDK等接口形式。 - **Primary Language**: Java - **License**: Apache-2.0 - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 1 - **Forks**: 2 - **Created**: 2021-07-23 - **Last Updated**: 2022-04-22 ## Categories & Tags **Categories**: Uncategorized **Tags**: test-framework, java-sdk-test, cucumber-springboot-allure, gRPC-API-test ## README English, please click [here](./HELP.md) # 一款完备实用的API自动化测试框架 ## 目录 * 1. REST API的自动化测试 * 1.1 验证所有发布的 API 是否都能工作(冒烟测试) * 1.2 编写符合实际业务需求的 API 测试用例(功能测试) * 1.3 构造微服务 mock server,根据不同的请求返回不同的响应指定结果 (集成测试)] * 2. RPC API的自动化测试 * 2.1 json-RPC API的自动化测试 * 2.2 gRPC API的自动化测试 * 2.3 适用于 json-RPC API 的 mock server * 2.4 适用于 gRPC API 的 mock server * 3. SDK自动化测试 ```text 微服务时代,API的主要实现方式有 REST, RPC 以及近来比较流行的SDK三种。不同的接口形式,理所当然需要对应不同的测试方法。 ``` ### 1 REST API的自动化测试 #### 1.1 验证所有发布的 API 是否都能工作(冒烟测试) ##### 测试方法 ```text 1. 根据微服务提供的 OPEN API 文件,得到其对外提供的所有 REST API 列表(包括路径、方法、请求消息体结构和接收消息体结构等) 2. 构造请求消息体时: - 对于简单数据类型(如:integer, number, string, boolean),赋值为此数据类型在此 OPEN API 文件中定义的最大边界值。 - 对于复合数据类型(object 和 array),有明确子数据类型定义的,按定义赋值;无明确子数据类型定义的,统一按string类型处理。 3. 验证响应消息时: - 验证响应码是否等于 OPEN API 中定义的预期值 - 验证响应消息体结构: - 简单数据类型仅验证返回的数据类型是否与 OPEN API 文件中预定义的类型匹配,不要求值匹配; - 复合数据类型 object,需要验证响应消息中是否包含所有的期望 key ,以及匹配 value 的数据类型是否匹配期望; - 复合数据类型 array,需要验证响应消息中是否包含复合类型 object ?是,则需要验证 key 和数据类型;否则仅需要验证数据类型是否匹配期望。 ``` ##### 用例参考 - [点击此链接](./resources/features/sanitytest/backend.feature) - ![结果截图](./gallery/sanity_test.png) ##### 优点 ```text - 无需测试人员手动编写测试脚本,测试框架全自动完成 OpenAPI 分析及 REST 消息的发送和结果验证。 - 根据不同微服务的自我定义,自动适配其支持的协议类型(如,http, https, http2等)进行消息的发送和接收。 - 执行速度快,436个 API,请求和验证可以在40秒内完成。 ``` ##### 局限性 ```text - 未考虑实际的业务需求;仅限于最基本的可行性验证。 - 返回失败的请求需要人工二次校验其准确性(如果事先把测试数据准备好,则可规避此问题,但需要付出更多的人力)。 ``` #### 1.2 编写符合实际业务需求的 API 测试用例(功能测试) ##### 测试方法 1. 准备json格式的测试数据,包括: - 发送请求实时数据 - 接收响应实时数据 [格式参考](./resources/testdatacollection/v2.2.0/runtime/user_management/UserController.json) - (可选)需要预先存储到数据库的准备数据 [格式参考](./resources/testdatacollection/v2.1.0/testdata/orgUser.json) 注意: - 用于REST消息发送/接收的json数据文件应保留所有的域。某个域若无值,则填写null。 - 数据库预处理json数据文件无特别要求。 2. 编写脚本将请求数据发送给指定目的微服务。 3. 测试框架根据测试人员提供的接收响应数据,进行消息结果验证: - 符合预期,则测试通过; - 否则打印错误断言,测试退出并标记为失败。 ##### 用例参考 - [点击此链接](./resources/features/apitest/restful/user_management/user_register.feature) ##### 优点 ```text - 用例编写简单,核心测试脚本仅数行。 - 消息的发送、接收以及结果验证对用例编写人员透明。测试用例编写人员需要关心的只是产品业务需求。 - 测试数据与功能需求关联,支持复用。不同测试脚本(用例)可使用相同测试数据。 ``` ##### 局限性 ```text - 更多需要讨论的是 API 测试本身的局限性,和本测试框架无关。 ``` #### 1.3 构造微服务 mock server,根据不同的请求返回不同的响应指定结果 (集成测试) ##### 测试方法 ```text mock server既可以与具体的测试用例集成,也可以被部署为一个真实服务供客户端服务(在开发中的测试服务对象)调用; ``` 作为服务单独部署: 1. 当模拟为一个单独的服务,则修改[application.yml](./src/main/resources/application.yml)中参数 serviceMock.mocker,赋值为某一个具体的服务名称; 若希望在一个服务器中模拟所有服务,则修改上述参数的值为allRestInOne; 2. 准备json格式的请求和响应数据,存放在servicemocks目录,文件名与模拟的服务名保持一致; 3. 执行命令行命令 gradlew build,将生成的 jar 拷贝到目的服务器,或者通过 Dockerfile 生成镜像; 4. 启动命令:java -jar auto-test-1.0.0-SNAPSHOT.jar --server.ssl.enabled=<> --server.port=<> - 参数1:是否启用https,默认为false。 - 参数2:服务端侦听端口,默认为8080。 5. 工作原理说明: - mock server每收到一条 REST 请求,就会读取一次 json 格式的测试数据一次; - mock server将逐一匹配请求数据的每一个域,最后返回与请求数据匹配度最高的某个测试数据中response域的值; - 即,不同的两个测试数据,可以仅有一个域的值不同;mock server进行精确匹配,返回匹配成功的那个数据的response域值; - 如果找不到合适的测试数据进行匹配,则返回失败码400(bad request); - [数据格式参考](./servicemocks/backend.json) 与测试用例集成: 1. 准备json格式的请求和响应数据,存放在servicemocks目录,文件名与模拟的服务名保持一致; 2. 启动测试; 3. 待mock server收到请求并返回响应后(可通过在测试用例中添加定时器实现等待),通过时间戳进行交易日志(路径:/target/cucumber/log/autotest_custom.log)过滤,判断是否已收到请求和请求是否与期望一致。 ##### 实现参考 [点击链接](./src/main/java/pers/qinxie/autotest/servicemock/rest/RestMockController.java) ##### 优点 ```text 1. 测试数据支持动态修改,无需重启服务。 2. 返回结果支持参数化,即可以根据请求路径中的参数,动态替换返回结果中对应的参数的值。 3. 适配客户端http/https请求模式并响应;HTTP协议支持HTTP1.X和HTTP2, HTTP2同时支持h2和h2c。 - 如何在本机生成证书?使用命令: keytool -genkey -alias netty-reactor -storetype PKCS12 -keyalg RSA -keysize 2048 -keystore keystore.p12 -validity 3650 - 相关参数应根据在application.properties内的定义进行修改 - curl命令验证例子: curl -H "Content-Type:application/json" -X POST -d '{"user_id": "123", "coin":100, "success":1, "msg":"OK!" }' -v --http2-prior-knowledge http://172.22.17.74:8080/userservice/fedFromOrg/87654321 ``` ##### 持续改进 ```text 1. 需要支持插件等形式,对响应数据进行用户/请求差别化地动态修改(如,变量替换,实时算法调用等) ``` ### 2 RPC API的自动化测试 ```text RPC形式的API,又以 gRPC 和 json-RPC 两种实现方式居多。 ``` #### 2.1 [json-RPC](https://www.jsonrpc.org/specification) API的自动化测试 ```text 从 json-RPC 的规范我们可以知道,相比较于 REST ,jsonRPC 消息有如下几个特点: - 净荷消息由 HTTP1.1 承载; - 请求方法仅有 POST 一种; - 请求消息头(Header)中 Content-Type 必须是 application/json; - 请求消息体(Request Body)中必须包含 json-RPC 的关键字属性: - jsonrpc = "2.0" - id = 2 - method = [rpc method] 由此可见,json-RPC API的测试方法,和 REST API 的测试方法基本相同。 ``` #### 2.2 [gRPC](https://grpc.io/) API的自动化测试 ##### 测试方法 1. 获取 gRPC 接口定义的 [proto](https://developers.google.com/protocol-buffers/docs/proto3)文件,存放在对应测试版本的测试数据文件夹下([参考存放路径](/src/test/resources/testdatacollection/chain33/))。 - 根据实际情况判断(如,存在重名类等)是否需要在 proto 文件中指定输出的 java 类名(option java_outer_classname = "RpcProto";) - 需要生成service类(option java_generic_services = true;) 2. 通过 gradle 插件命令生成java class。可携带参数chainVer,表示proto文件版本。 - gradlew generateProto -DchainVer=v1.6.6 3. 编写 gRPC 客户端请求数据文件([参考链接](./resources/testdatacollection/v2.2.0/runtime/chain_ops/sendTransaction.json)) 3. 由于 gRPC 接口对负载净荷数据有其自定义的规范要求,所以只能手工实现请求数据的类型转换,然后发送和响应数据的验证: - 编写 gRPC 客户端发送程序代码(主要是把步骤3中的数据,序列化成2进制码流。[参考链接](./src/main/java/com/fuzamei/autotest/rpc/grpc/GrpcClientTransaction.java)) - 编写 gRPC 服务端响应数据验证代码(主要是和 proto 文件中定义的 service.returns 进行结果比对)。 ##### 用例参考 - [点击此链接](./resources/features/apitest/grpc/accountManager.feature) ##### 优点 ```text - N/A ``` ##### 持续改进 ```text - 对于语法不完整的 proto 文件,无法实现自动化验证; - 相对 RESTful 接口自动化测试用例来说,RPC接口自动化测试用例需要更多的代码编写量; - 需要找寻一个通用的解决方案去实现:测试数据与实际发送数据类型的自动转换机制。 ``` #### 2.3 适用于 json-RPC API 的 mock server [参考 1.1.3 实现](#a-idchapter113113--mock-server-a) #### 2.4 适用于 gRPC API 的 mock server ##### 测试方法 与 [1.1.3](#a-idchapter113113--mock-server-a) 方法大体相同,但仍然存在如下区别: ```text 1. 因为 protobuf 协议的差异性,必须手动编写proto文件中service定义的实现类。 2. gRPC服务端默认侦听端口为8802,可通过传入参数 --grpc.server.port=<> 来指定。 ``` ##### 实现参考 [点击链接](./src/main/java/pers/qinxie/autotest/servicemock/grpc/GrpcServerService.java) ##### 优点 ```text 1. REST API和 gRPC API的mock server可部署在同一台机器,同时启动且不互相冲突(前提是保证侦听端口不一样)。 ``` ##### 持续改进 ```text 需要找寻一个通用的解决方案去实现:测试数据与实际发送数据类型的自动转换机制。从而减少业务代码的编写,测试人员需要关心的只是测试数据和业务流程验证。 ``` ## 3. SDK自动化测试 ```text SDK(Software Development Kit)是为第三方开发者提供的软件开发工具包,包括SDK接口、开发文档和Demo示例等。 SDK自动化测试目标性很强,一般都是为了验证某些个特定业务场景的测试。所以很难抽象出一些公共或通用方法去处理这类的测试。 ``` ##### 用例参考 - [点击此链接](./resources/features/sdktest/storage.feature)