[i18n] print_printable_section [i18n] print_click_to_print.
任务
- 1: 快速入门
- 2: gRPC TLS verification
- 3: gRPC测试用例编写指南
- 4: Mock 服务
- 5: 测试用例验证
- 6: 插件
- 7: 代码生成
- 8: 关于安全
1 - 快速入门
本指南将帮助您通过几个简单的步骤开始使用 API Testing。
执行部分测试用例
下面的命令会执行名称中包含 sbom
的所有测试用例:
atest run -p test-suite.yaml --case-filter sbom
2 - gRPC TLS verification
If you want to enable gRPC TLS, you need to generate your certificates in the workspace, or you can use an absolute path
1. 生成私钥
openssl genrsa -out server.key 2048
2. 生成证书(会提示即可,不必填写)
openssl req -new -x509 -key server.key -out server.crt -days 36500
国家名字
Country Name (2 letter code) [AU]:CN
省份全名
State or Province Name (full name) [Some-State]:GuangDong
城市名
Locality Name (eg, city) []:Meizhou
组织名
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Xuexiangban
组织单位名
Organizational Unit Name (eg, section) []:go
服务器or用户的名字
Common Name (e.g. server FQDN or YOUR name) []:kuangstudy
邮箱地址
Email Address []:24736743@qq.com
3.生成csr
openssl req -new -key server.key -out server.csr
4.配置openssl.cfg
1) 查找openssl在服务器的安装目录并且找到openssl.cnf
2) 编辑[ CA_default ] ,打开 copy_extensions = copy #取消注释
3) 找到[ req ],打开 req_extensions = v3.req #取消注释
4) 找到[ v3_req ],添加字段 subjectAltName = @alt_names
5) 添加新的标签在最底部 [ alt_names ]和标签字段
DNS.1 = localhost
5.生成本地私钥test.key
openssl genpkey -algorithm RSA -out test.key
6.根据私钥生成csr请求文件test.csr
openssl req -new -nodes -key test.key -out test.csr -days 3650 \
-subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=www.example.com" \
-config ./openssl.cnf -extensions v3_req
7.生成ca证书 pem
openssl x509 -req -days 365 -in test.csr \
-out test.pem -CA server.crt -CAkey server.key \
-CAcreateserial -extfile ./openssl.cnf -extensions v3_req
3 - gRPC测试用例编写指南
本文档将介绍如何编写api-testing
的 gRPC API 的测试用例。
阅读本文档之前,您需要先安装并配置好api-testing
,具体操作可以参考安装章节。如果您已经完成了这些步骤,可以继续阅读本文档的后续部分。
创建测试项目
创建一个基于服务反射的 gRPC 测试用例仅需在 yaml 文件的spec
路径下加入以下内容:
spec:
rpc:
serverReflection: true
rpc
字段一共有五个子字段
字段名 | 类型 | 是否可选 |
---|---|---|
import | []string | √ |
protofile | string | √ |
protoset | string | √ |
serverReflection | bool | √ |
字段import
和protofile
protofile
是一个文件路径,指向api-testing
查找描述符的.proto
文件的位置。
import
字段与protc
编译器中的--import_path
参数类似,用于确定查找proto
文件的位置与解析依赖的目录。与protoc
一样,您不需要在此处指定某些proto
文件的位置(以google.protobuf
开头的Protocol Buffers Well-Known Types
),它们已经内置在了api-testing
中。
字段protoset
protoset
字段既可以是一个文件路径,也可以是http(s)://
开头的网络地址。
当您的proto
数量繁多或引用关系复杂,可以尝试使用protoc --descriptor_set_out=set.pb
生成proto
描述符集合。本质上它是一个使用了wire
编码的二进制文件,其中包括了所有需要的描述符。
字段serverReflection
若目标服务器支持服务反射,将此项设为true
则不再需要提供上述三个字段。
注:api-testing
对三种描述符来源的优先级顺序为
serverReflection
> protoset
> protofile
编写gRPC API测试
与编写HTTP
测试用例类型,您需要在根节点的api
字段定义服务器的地址。
api: 127.0.0.1:7070
默认情况下api-testing
使用不安全的方式连接到目标服务器。若您想配置TLS证书,请参考文档关于安全
编写gRPC API
测试的方式与编写HTTP API
测试的方式基本相同。
- name: FunctionsQuery
request:
api: /server.Runner/FunctionsQuery
body: |
{
"name": "hello"
}
expect:
body: |
{
"data": [
{
"key": "hello",
"value": "func() string"
}
]
}
api
字段的格式为/package.service/method
,支持 gRPC 一元调用、客户端流、服务端流和双向流调用。
与api
字段同级的body
字段是以JSON
格式表示的Protocol Buffers
消息,代表将要调用的api
的入参。特别的,当您需要调用客户端流或双向流 API 时,请使用JSON Array
格式编写字段body
,如:
body: |
[
{
"name": "hello"
},
{
"name": "title"
}
]
编写返回内容验证
编写gRPC API
返回内容验证的方式与HTTP API
基本相同。对与gRPC API
来说,一切返回值都被视为map
类型,被放入api testing
特定的返回结构中:
expect:
body: |
{
"data": [
{
"key": "hello",
"value": "func() string"
}
]
}
api-testing
为JSON
比对编写了一套对比库,请参考此处compare
请注意,对于服务端流和双向流模式,服务器发送多条消息的情况下,此处的data
字段内的填写的目标数组,需同时满足与待验证数组长度相,两个数组同一下标的内容完全相同。
gRPC API
的verify
功能与HTTP API
保持一致,此处不再赘述。
4 - Mock 服务
Mock 服务在前后端并行开发、系统对接、设备对接场景下能起到非常好的作用,可以极大地降低团队之间、系统之间的耦合度。
用户可以通过命令行终端(CLI)、Web UI 的方式来使用 Mock 服务。
命令行
atest mock --prefix / --port 9090 mock.yaml
Web
在 UI 上可以实现和命令行相同的功能,并可以通过页面编辑的方式修改、加载 Mock 服务配置。
Mock Docker Registry
您可以通过执行下面的命令 mock 一个容器仓库服务container registry:
atest mock --prefix / mock/image-registry.yaml
之后,您可以通过使用如下的命令使用 mock 功能。
docker pull localhost:6060/repo/name:tag
语法
从整体上来看,我们的写法和 HTTP 的名称基本保持一致,用户无需再了解额外的名词。此外,提供两种描述 Mock 服务的方式:
- 面向对象的 CRUD
- 自定义 HTTP 服务
面对对象
#!api-testing-mock
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-mock-schema.json
objects:
- name: projects
initCount: 3
sample: |
{
"name": "atest",
"color": "{{ randEnum "blue" "read" "pink" }}"
}
上面 projects
的配置,会自动提供该对象的 CRUD(创建、查找、更新、删除)的 API,你可以通过 atest
或类似工具发出 HTTP 请求。例如:
curl http://localhost:6060/mock/projects
curl http://localhost:6060/mock/projects/atest
curl http://localhost:6060/mock/projects -X POST -d '{"name": "new"}'
curl http://localhost:6060/mock/projects -X PUT -d '{"name": "new", "remark": "this is a project"}'
curl http://localhost:6060/mock/projects/atest -X DELETE
initCount
是指按照sample
给定的数据初始化多少个对象;如果没有指定的话,则默认值为 1.
自定义
#!api-testing-mock
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-mock-schema.json
items:
- name: prList
request:
path: /api/v1/repos/{repo}/prs
response:
header:
server: mock
Content-Type: application/json
body: |
{
"count": 1,
"items": [{
"title": "fix: there is a bug on page {{ randEnum "one", "two" }}",
"number": 123,
"message": "{{.Response.Header.server}}",
"author": "someone",
"status": "success"
}]
}
启动 Mock 服务后,我们就可以发起如下的请求:
curl http://localhost:6060/mock/api/v1/repos/atest/prs -v
另外,为了满足复杂的场景,还可以对 Response Body 做特定的解码,目前支持:base64
、url
:
#!api-testing-mock
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-mock-schema.json
items:
- name: base64
request:
path: /api/v1/base64
response:
body: aGVsbG8=
encoder: base64
上面 Body 的内容是经过 base64
编码的,这可以用于不希望直接明文显示,或者是图片的场景:
curl http://localhost:6060/mock/api/v1/base64
如果你的 Body 内容可以通过另外一个 HTTP 请求(GET)获得,那么你可以这么写:
#!api-testing-mock
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-mock-schema.json
items:
- name: baidu
request:
path: /api/v1/baidu
response:
body: https://baidu.com
encoder: url
在实际情况中,往往是向已有系统或平台添加新的 API,此时要 Mock 所有已经存在的 API 就既没必要也需要很多工作量。因此,我们提供了一种简单的方式,即可以增加代理的方式把已有的 API 请求转发到实际的地址,只对新增的 API 进行 Mock 处理。如下所示:
#!api-testing-mock
# yaml-language-server: $schema=https://linuxsuren.github.io/api-testing/api-testing-mock-schema.json
proxies:
- path: /api/v1/{part}
target: http://atest.localhost:8080
当我们发起如下的请求时,实际请求的地址为 http://atest.localhost:8080/api/v1/projects
curl http://localhost:6060/mock/api/v1/projects
更多 URL 中通配符的用法,请参考 https://github.com/gorilla/mux
5 - 测试用例验证
atest
采用 https://expr.medv.io 对 HTTP 请求响应的验证,比如:返回的数据列表长度验证、具体值的验证等等。下面给出一些例子:
需要注意的是,
data
指的是 HTTP Response Body(响应体)的 JSON 对象。
数组长度判断
- name: projectKinds
request:
api: /api/resources/projectKinds
expect:
verify:
- len(data.data) == 6
数组值检查
- name: popularHeaders
request:
api: /popularHeaders
expect:
verify:
- any(data.data, {.key == "Content-Type"})
更多用法.
字符串判断
- name: metrics
request:
api: |
{{.param.server}}/metrics
expect:
verify:
- indexOf(data, "atest_execution_count") != -1
更多用法.
6 - 插件
atest
会把非核心、可扩展的功能以插件(extension)的形式实现。下面介绍有哪些插件,以及如何使用:
在不同的系统中,插件有着不同的表述,例如:extension、plugin 等。
类型 | 名称 | 描述 |
---|---|---|
存储 | orm | 保存数据到关系型数据库中,例如:MySQL |
存储 | s3 | 保存数据到对象存储中 |
存储 | etcd | 保存数据到 Etcd 数据库中 |
存储 | git | 保存数据到 Git 仓库中 |
存储 | mongodb | 保存数据到 MongDB 中 |
atest
也是唯一支持如此丰富的存储的接口开发、测试的开源工具。
下载插件
我们建议通过如下的命令来下载插件:
atest extension orm
上面的命令,会识别当前的操作系统,自动下载最新版本的插件。当然,用户可以通过自行编译、手动下载的方式获取插件二进制文件。
atest
可以从任意支持 OCI 的镜像仓库中(命令参数说明中给出了支持的镜像服务地址)下载插件,也可以指定下载超时时间:
atest extension orm --registry ghcr.io --timeout 2ms
8 - 关于安全
通常在不使用 TLS 证书认证时,gRPC 客户端与服务端之间进行的是明文通信,信息易被第三方监听或篡改。所以大多数情况下均推荐使用 SSL/TLS 保护 gRPC 服务。目前atest
已实现服务端 TLS,双向 TLS(mTLS) 需等待后续实现。
默认情况下atest
不使用任何安全策略,等价于spec.secure.insecure = true
。启用 TLS 仅需 yaml 中添加以下内容:
spec:
secure:
cert: server.pem
serverName: atest
字段说明
secure
共有以下五个字段:
字段名 | 类型 | 是否可选 |
---|---|---|
cert | string | x |
ca | string | √ |
key | string | √ |
serverName | string | x |
insecure | bool | √ |
cert
为客户端需要配置的证书的文件路径,格式为PEM
。
serverName
为 TLS 所需的服务名,通常为签发证书时使用的 x509 SAN。
ca
为 CA 证书的路径,key
为与cert
对应的私钥,这两项填写后代表启用 mTLS。(mTLS 尚未实现)
当insecure
为false
时,cert
和serverName
为必填项。