美文网首页
e2e测试,实现自动化联调

e2e测试,实现自动化联调

作者: 周群力 | 来源:发表于2023-08-28 09:16 被阅读0次

概念

e2e测试,a.k.a.“自动化联调”,模拟最终用户的操作、看效果。
不需要mock/fake环境,依赖多个系统的真实环境。

优点:

  • 相比于UT、集成测试:
    • 更贴近真实场景,更能发现问题
    • 写测试用例的成本更低(因为不需要mock/fake环境)
  • 相比于人工联调:
    • 省去联调时大量的沟通协作成本、人肉操作成本
    • 全链路任何一个系统发生变更后(代码变更或配置变更),可以自动化回归测试
  • 方便对环境做故障注入,看系统在特定故障时的表现

更详细的概念介绍:
https://circleci.com/blog/what-is-end-to-end-testing/

Design choices

怎么触发、怎么setup环境

A. CI 里触发,原地创建环境、跑测试

创建环境可以基于k8s:

  • 先调k8s接口,删除原先的资源
  • 然后再通过kubectl(或者调k8s接口)创建(联调需要用到的)环境。

没有k8s的话也可以基于 docker或者 docker-compose 创建环境。

B. merge后持续部署,部署完成后自动触发E2E测试

触发后需要保证互斥执行,避免并发跑测试。

pros:

  • 写test case不需要mock不需要fake,省去setup环境的工作

cons:

  • 条件可能比较苛刻。比如,如果e2e测试依赖多个系统,需要:
    • 多个系统都设置持续部署
    • 并发部署时,有个编排系统,保证互斥、避免重复执行。

C. 定时巡检

巡检脚本可以临时找机器做测试,也可以使用固定的机器做测试
pros:

  • 写test case不需要mock不需要fake,省去setup环境的工作
  • 和部署方案解耦,条件没B方案那么苛刻,成本低

多分支开发,但测试环境只有一套,怎么办?

A. CI里创建环境,让测试环境有多套
B. 针对指定分支(例如develop) 设置持续部署。要求所有分支上线前都得合并进这个分支,合并后触发自动部署。

案例分析

K8s 如何做e2e测试

怎么触发e2e测试

CI 里触发,原地创建 K8s集群,然后跑测试

触发e2e测试后,会发生什么

  1. 工具链会创建并启动一个测试用的K8s集群(或者使用现有集群)

  2. 跑 E2E 测试用例。

这些测试用例本质上是K8s的客户端,它们会调 K8s的接口、使用K8s、断言预期效果。

  1. 清理掉临时的K8S集群

详见
https://blog.gmem.cc/kubernetes-e2e-test

例子

测试Pod能读取secret

  1. 准备好yaml,调用Kubectl来创建Secret、创建会读取此Secret并打印的Pod
  2. 等待Pod退出
  3. 检查Pod日志,断言出现了关键词

// 声明一个ginkgo.Describe块,自动添加[k8s.io] 标签
var _ = framework.KubeDescribe("[Feature:Example]", func() {
    //省略……
    
    framework.KubeDescribe("Secret", func() {
        // 第二个Spec,测试Pod能读取一个保密字典
        ginkgo.It("should create a pod that reads a secret", func() {
            test := "test/fixtures/doc-yaml/user-guide/secrets"
            secretYaml := readFile(test, "secret.yaml")
            podYaml := readFile(test, "secret-pod.yaml.in")
 
            nsFlag := fmt.Sprintf("--namespace=%v", ns)
            podName := "secret-test-pod"
 
            ginkgo.By("creating secret and pod")
            // 创建一个Secret,以及会读取此Secret并打印的Pod
            framework.RunKubectlOrDieInput(secretYaml, "create", "-f", "-", nsFlag)
            framework.RunKubectlOrDieInput(podYaml, "create", "-f", "-", nsFlag)
            // 等待Pod退出
            err := e2epod.WaitForPodNoLongerRunningInNamespace(c, podName, ns)
            framework.ExpectNoError(err)
 
            ginkgo.By("checking if secret was read correctly")
            // 检查Pod日志
            _, err = framework.LookForStringInLog(ns, "secret-test-pod", "test-container", "value-1", serverStartTimeout)
            framework.ExpectNoError(err)
        })
    })
}

测试健康检查失败的Pod能否自动重启

  1. 准备好yaml,调用Kubectl来创建资源
  2. 轮询调接口,查该pod的重启次数
  3. 如果在一定时间内没满足预期,就报错

和其他系统集成(联调)的案例

  • K8s + Helm

https://github.com/kubernetes-sigs/e2e-framework/tree/main/examples/third_party_integration/helm

  • K8s + Flux

https://github.com/kubernetes-sigs/e2e-framework/tree/main/examples/third_party_integration/flux

怎么断言别的Pod内发生了什么

写测试用例时,可以使用社区的测试框架,框架提供了实用的Utils库,例如,提供了用于断言“日志中出现关键词”的函数

怎么模拟各种异常场景

  • 框架有提供一些工具函数,例如:
image.png
  • 框架提供NodeKiller,负责周期性的模拟节点失败
if framework.TestContext.NodeKiller.Enabled {
    nodeKiller := framework.NewNodeKiller(framework.TestContext.NodeKiller, c, framework.TestContext.Provider)
    // NodeKiller负责周期性的模拟节点失败
    go nodeKiller.Run(framework.TestContext.NodeKiller.NodeKillerStopCh)
}
  • 自己操作pod,在pod里执行命令
  • 在自己创建的pod里写程序、制造故障

代理软件如何做e2e测试

Dapr

image.png

怎么触发e2e测试

提PR后,可以在 CI里触发(需要 maintainer or approver 在PR里评论 /ok-to-test),会用预先准备好的 AKS 集群跑测试。

也可以用自己的 K8s 集群,手动触发、跑测试。

触发e2e测试后,会发生什么

  1. 调 K8s,部署dapr代理的 redis/kafka/mongodb等系统
  2. 部署dapr:构建,打包成镜像,发布到镜像仓库,调K8s部署镜像
  3. 配置dapr。Register the default component configurations for testing
  4. 跑e2e测试:构建e2e app,打包成镜像,发布到镜像仓库,调K8s部署,运行e2e app

https://github.com/dapr/dapr/blob/master/tests/docs/running-e2e-test.md#user-content-run-e2e-tests-in-local-dev-environment

e2e测试的例子

https://github.com/dapr/dapr/blob/master/tests/docs/writing-e2e-test.md

State测试

以 state 的测试为例:

image.png
Test drive

包含真正的test case,本质是客户端,断言发包收包结果。
比如“写-读-删-读”测试,断言每一步收到的response:

image.png

每一步读写操作其实是发http请求调 test app,由 test app 调dapr
https://github.com/dapr/dapr/blob/master/tests/e2e/stateapp/stateapp_test.go#L396

Test app

收到 Test driver 的命令,给dapr 发请求
https://github.com/dapr/dapr/blob/master/tests/apps/stateapp/app.go#L464

image.png
RPC测试
image.png
Test driver

https://github.com/dapr/dapr/blob/master/tests/e2e/service_invocation/service_invocation_test.go#L79
https://github.com/dapr/dapr/blob/master/tests/e2e/service_invocation/service_invocation_test.go#L229
[图片上传失败...(image-acb490-1693271805183)]

Test app

https://github.com/dapr/dapr/blob/master/tests/apps/service_invocation/app.go#L174

https://github.com/dapr/dapr/blob/master/tests/apps/service_invocation/app.go#L299

咋断言upstream收到了某个包?

看起来没断言upstream 收到的包,只是断言 client 收到的最终response

Layotto

https://mosn.io/layotto/#/zh/development/test-quickstart

CI 里原地创建环境。没依赖 k8s,基于 docker或者 docker-compose 创建环境。
运行测试用例,本质是客户端,断言发包收包结果。

有UI的APP/网站如何做e2e测试

支付宝首页助理

定时巡检测试:

  • 下发假数据
  • 调前端接口
  • assert接口返回的数据内容

以上测试直接在线上/预发环境运行,用于变更后测试,及时发现变更引入的问题,包括全链路任何一个系统的配置变更、代码变更

高级功能

如何在pod内实现故障注入

方案:测试用例在目标pod 中运行,因此测试用例有权限原地制造故障
缺点:只能在本pod内制造故障,没法跨pod/跨节点故障注入

如何跨pod操作(例如跨pod故障注入、跨pod查日志)

A. 给所在节点添加 DaemonSet,DaemonSet 想办法侵入其他pod的namespace、干扰其他pod

参考 chaos mesh

B. 远程登录指定pod,然后执行shell命令

缺点:远程登录有权限问题

C. 基于K8s API 让其他pod执行shell

D. pod内安插间谍(后门)

Q: 如何植入后门?

方案A. 可以在给相关 pod 内添加守护进程/sidecar容器;
好处是不侵入业务进程
缺点:
新起一个进程有一定的开发成本;

方案B. 直接在目标pod的业务进程里实现后门功能(可以通过引入一个库来自动实现,减少侵入性);

Q: 后门如何对外暴露接口?

方案A. 每个服务开放debug接口 (RPC/IPC 接口),用于跨pod操作(例如故障注入,读取日志等);

方案B. 不开接口,test app依赖有watch机制的外部存储,一个节点写入命令,另一个节点watch、执行命令
难点是怎么保证只执行一次

Q: 编程界面?

方案A. 参考k8s,设计utils 库,用于在指定的pod执行操作:
[图片上传失败...(image-56c068-1693271805183)]

相关文章

网友评论

      本文标题:e2e测试,实现自动化联调

      本文链接:https://www.haomeiwen.com/subject/ysdgmdtx.html