尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

KubeEdge 的 E2E 测试基石:Ginkgo BDD 测试框架的 DSL、CLI 与实战应用

KubeEdge 的 E2E 测试基石:Ginkgo BDD 测试框架的 DSL、CLI 与实战应用 KubeEdge 的 E2E 测试基石Ginkgo BDD 测试框架的 DSL、CLI 与实战应用【免费下载链接】kubeedgeKubernetes Native Edge Computing Framework (project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/ku/kubeedgeGinkgo 是 KubeEdge 仓库中承载全部端到端e2e与集成测试的核心测试框架。本篇以仓库中 vendor 引入的 Ginkgo v2 官方 READMEvendor/github.com/onsi/ginkgo/v2/README.md为主体完整梳理其 BDD 风格 DSL、节点体系、并行执行、标签过滤与 CLI 工具能力并结合 KubeEdge 自身的 tests/e2e/e2e_test.go 与 tests/scripts/execute.sh 等真实用例说明这一框架在 KubeEdge 中如何落地为可运行的端到端测试流水线。什么是 Ginkgo构建在 Go testing 之上的 BDD 测试框架Ginkgo 官方 README 将其定位为一个面向 Go 的成熟测试框架mature testing framework构建在 Go 标准库testing之上并与 Gomega 匹配器matcher库配套使用。二者组合的目标是让规格spec清晰表达意图——这一点在 KubeEdge 的 e2e 测试中体现得很明显测试代码读起来接近自然语言描述而非命令式的断言堆叠。README 中给出的经典示例是一个图书馆借书场景它几乎涵盖了 Ginkgo 的全部核心 DSL 元素import ( . github.com/onsi/ginkgo/v2 . github.com/onsi/gomega ... ) var _ Describe(Checking books out of the library, Label(library), func() { var library *libraries.Library var book *books.Book var valjean *users.User BeforeEach(func() { library libraries.NewClient() book books.Book{ Title: Les Miserables, Author: Victor Hugo, } valjean users.NewUser(Jean Valjean) }) When(the library has the book in question, func() { BeforeEach(func(ctx SpecContext) { Expect(library.Store(ctx, book)).To(Succeed()) }) Context(and the book is available, func() { It(lends it to the reader, func(ctx SpecContext) { Expect(valjean.Checkout(ctx, library, Les Miserables)).To(Succeed()) Expect(valjean.Books()).To(ContainElement(book)) Expect(library.UserWithBook(ctx, book)).To(Equal(valjean)) }, SpecTimeout(time.Second * 5)) }) Context(but the book has already been checked out, func() { var javert *users.User BeforeEach(func(ctx SpecContext) { javert users.NewUser(Javert) Expect(javert.Checkout(ctx, library, Les Miserables)).To(Succeed()) }) It(tells the user, func(ctx SpecContext) { err : valjean.Checkout(ctx, library, Les Miserables) Expect(err).To(MatchError(Les Miserables is currently checked out)) }, SpecTimeout(time.Second * 5)) It(lets the user place a hold and get notified later, func(ctx SpecContext) { Expect(valjean.Hold(ctx, library, Les Miserables)).To(Succeed()) Expect(valjean.Holds(ctx)).To(ContainElement(book)) By(when Javert returns the book) Expect(javert.Return(ctx, library, book)).To(Succeed()) By(it eventually informs Valjean) notification : Les Miserables is ready for pick up Eventually(ctx, valjean.Notifications).Should(ContainElement(notification)) Expect(valjean.Checkout(ctx, library, Les Miserables)).To(Succeed()) Expect(valjean.Books(ctx)).To(ContainElement(book)) Expect(valjean.Holds(ctx)).To(BeEmpty()) }, SpecTimeout(time.Second * 10)) }) }) When(the library does not have the book in question, func() { It(tells the reader the book is unavailable, func(ctx SpecContext) { err : valjean.Checkout(ctx, library, Les Miserables) Expect(err).To(MatchError(Les Miserables is not in the library catalog)) }, SpecTimeout(time.Second * 5)) }) })这个示例值得逐段拆解因为它同时展示了容器节点Describe/When/Context的嵌套组织、BeforeEach前置准备、It主体断言、By步骤注释、SpecTimeout节点级超时以及Eventually异步断言——这些都是 KubeEdge e2e 测试中会反复用到的能力。README 指出这种风格的测试常被称为行为驱动开发Behavior-Driven Development, BDD来自 Quick、RSpec、Jasmine、Busted 等框架的用户可以很快上手但 Ginkgo 的用途并不局限于验收级测试从基础单元测试到复杂的集成测试、甚至性能测试都可以覆盖。节点体系从组织 spec 到管理测试套件生命周期README 将 Ginkgo 的 DSL 能力归纳为几类节点逐一说明如下容器节点Container Nodes可嵌套的Describe、Context与When用于组织 spec 的层级结构。在借书示例中When划分了图书馆有此书/无此书两条大分支Context进一步区分书可借/书已被借出两种状态形成一棵可读性很强的用例树。设置与清理节点Setup NodesBeforeEach与AfterEach负责公共的初始化与清理。注意BeforeEach可以逐层叠加外层初始化 library/book/valjean内层再补充特定场景的准备如让 Javert 先借走书。主体节点Subject NodesIt与Specify承载真正的断言逻辑。套件级节点Suite-level NodesBeforeSuite与AfterSuite在整个测试套件开始之前、结束之后各执行一次适合做进程级的准备与收尾。KubeEdge 的 e2e 入口正是BeforeSuite/AfterSuite的典型用法。在 tests/e2e/e2e_test.go 中func TestE2E(t *testing.T) { gomega.RegisterFailHandler(ginkgo.Fail) var _ ginkgo.BeforeSuite(func() { utils.Infof(Before Suite Execution) if utils.LoadConfig().TestDevice { err : utils.MqttConnect() gomega.Expect(err).To(gomega.BeNil()) } }) ginkgo.AfterSuite(func() { ginkgo.By(After Suite Execution....!) }) // ... suiteConfig, reporterConfig : framework.CreateGinkgoConfig() ginkgo.RunSpecs(t, KubeEdge e2e suite, suiteConfig, reporterConfig) }这里BeforeSuite在配置要求测试设备时建立 MQTT 连接RegisterFailHandler(ginkgo.Fail)则打通了 Gomega 断言失败与 Ginkgo 失败报告之间的链路而RunSpecs负责真正驱动整个套件的执行——这正是 README 所描述的构建在 Gotesting基础之上的接入方式Ginkgo 的入口仍然是标准 Go 测试函数TestE2E(t *testing.T)。另一处是 tests/e2e_keadm/keadm_suite_test.go它采用了 dot import. github.com/onsi/ginkgo/v2的写法BeforeSuite中初始化跨包共享的utils.NewTestContext(utils.LoadConfig())上下文最后RunSpecs(t, kubeedge App Deploymet Suite)启动套件。两处入口共同说明KubeEdge 的每个 e2e 模块e2e、e2e_keadm、e2e_edgesite都是一个独立的 Ginkgo 套件通过标准的TestXxx(t *testing.T)函数接入go test。随机顺序、并行执行与节点级超时控制README 强调的两个运行时能力值得重点关注可复现的随机顺序reproducibly random orderGinkgo 运行 spec 时会以可复现的方式随机打乱顺序用于暴露用例之间的隐藏依赖。spec 并行化并行执行简单到一条命令ginkgo -pREADME 特别提到遵循其推荐的并行集成 spec 编写模式后可以构建大型、复杂且能干净并行的集成测试套件。KubeEdge 的 e2e 恰好属于这类大规模集成场景要覆盖云侧、边缘侧、设备、规则引擎等多个平面。此外针对集成测试最常见的套件挂死或留下脏环境问题README 指出 Ginkgo 提供了两个关键机制每节点context.ContextREADME 的示例中BeforeEach(func(ctx SpecContext) {...})与It(..., func(ctx SpecContext) {...})都接收SpecContext参数异步操作可以绑定到该上下文按节点超时的中断与清理能力示例中每个It节点都附加了SpecTimeout(time.Second * 5)或SpecTimeout(time.Second * 10)装饰器超时后 Ginkgo 会中断该 spec 并执行清理。在 e2e 这种要真实拉起集群、连接 MQTT Broker 的场景里节点级超时意味着单个挂死的用例不会拖垮整个套件。标签、子集过滤与可组合的执行筛选README 指出当套件不断膨胀时Ginkgo 通过标签labels帮助组织 spec并支持以两种方式运行 spec 子集编程式的 focused specs与命令行过滤器且过滤器可以组合使用。示例代码中的Describe(Checking books out of the library, Label(library), ...)就是给整个容器节点打标签的写法之后即可用命令行按标签挑选子集运行。这一能力对应 KubeEdge 的实际运行方式其测试入口按模块拆分成独立二进制e2e、e2e_keadm、e2e_edgesitetests/scripts/fast_test.sh 中即通过选择具体的编译产物来挑选子集ginkgo -v ./e2e/e2e.test -- \ --image-urlnginx \ --kube-masterhttps://$MASTER_IP:6443 \ --kubeconfig$KUBECONFIG \ --test.v注意命令中--之后才是传给被测程序本身的 flag——这是 Ginkgo CLI 运行已编译测试二进制时的标准用法--前的参数归 ginkgo--后的参数如--kubeconfig、--test.v原样透传给测试二进制。KubeEdge 在 tests/e2e/e2e_test.go 的TestMain中注册了大量 flag含 k8s e2e framework 的公共 flag 与集群 flagfast_test.sh透传的正是其中一部分。关于报告输出README 说明 Ginkgo 的报告基础设施能生成多种格式的机器可读输出并且允许开发者自行构建定制的报告管线。KubeEdge 的 e2e 入口里当framework.TestContext.ReportDir非空时会先创建报告目录tests/e2e/e2e_test.go配合 CI 中 Jenkins 的 JUnit 报告需求机器可读报告正是这类自动化流水线消费的核心产物。ginkgo CLI生成、运行、过滤、剖析与 watchREADME 明确 Ginkgo 附带ginkgo命令行工具支持生成、运行、过滤与剖析profiling测试套件还有ginkgo watch模式在检测到代码变化时自动重跑 spec以支持测试驱动开发中的快速反馈循环。KubeEdge 仓库完整展示了这套 CLI 的工程化用法。tests/scripts/execute.sh 是 e2e 流水线的总入口关键步骤为which ginkgo /dev/null || ( go install github.com/onsi/ginkgo/v2/ginkgolatest sudo cp $GOPATH/bin/ginkgo /usr/local/bin/ )若系统没有ginkgo命令则通过go install安装 Ginkgo v2 的 CLI注意安装的是github.com/onsi/ginkgo/v2/ginkgo包路径下的命令行程序。随后流水线执行bash -x ${curpath}/tests/scripts/compile.sh ${compilemodule}tests/scripts/compile.sh 则展示了ginkgo build子命令——将 Ginkgo 套件编译成独立测试二进制# 未指定模块时编译全部 e2e 模块 ginkgo build e2e ginkgo build e2e_keadm ginkgo build e2e_edgesite # 指定模块时递归构建该模块 ginkgo build -r $compilemodule之所以要先ginkgo build再运行二进制而不是直接go test一方面是把构建耗时与执行耗时解耦另一方面也便于按模块选择执行对象。execute.sh随后用hack/local-up-kubeedge.sh基于 kind 拉起测试集群再调用fast_test.sh完成ginkgo -v xxx.test -- ...的实际执行最后依据GINKGO_TESTING_RESULT判定成败并执行 cleanup 收尾——这与 README 提到的不必担心套件挂死或留下脏环境的清理主题相呼应。Gomega同步与异步断言的统一表达README 将 Gomega 定位为 Ginkgo 的互补库为套件提供丰富且成熟的断言与匹配器家族。其亮点包括同步与异步断言自由混用借书示例中Expect(...)是同步断言而Eventually(ctx, valjean.Notifications).Should(ContainElement(notification))是异步断言——后者在时间窗口内轮询目标值直至条件成立天然适合Javert 还书后Valjean 最终收到通知这类时序不可控的场景用现有构件快速组合自定义领域匹配器README 指出可以基于 Gomega 的既有匹配器积木搭建自己的表达性断言。示例中出现的Succeed()、MatchError(...)、ContainElement(...)、Equal(...)、BeEmpty()都是这种匹配器家族的成员MatchError用于精确匹配错误信息Succeed用于断言无错误。Gomega 通过RegisterFailHandler(ginkgo.Fail)与 Ginkgo 的失败报告机制对接见 tests/e2e/e2e_test.go 与 tests/e2e_keadm/keadm_suite_test.go使得任何 Gomega 断言失败都能被 Ginkgo 正确归因到具体的 spec 节点并进入报告。版本与在 KubeEdge 仓库中的落地位置结合当前仓库事实go.mod 中声明的测试依赖为github.com/onsi/ginkgo/v2 v2.21.0与github.com/onsi/gomega v1.35.1此外还有一个 indirect 的 ginkgo v1.16.5来自上游 k8s 相关依赖。框架源码以 vendor 形式完整保留在 vendor/github.com/onsi/ginkgo/v2 下目录结构可见其模块划分core_dsl.go、ginkgo_t_dsl.go对接标准 testing 的入口、decorator_dsl.goSpecTimeout等装饰器、table_dsl.go、reporting_dsl.go、reporters/机器可读报告、types/配置与报告类型以及ginkgo/CLI 源码等——从源码结构看README 中描述的 DSL 节点、报告基础设施与命令行工具分别对应这些独立文件与子包职责边界清晰。KubeEdge 中 Ginkgo 的实际使用面集中在 tests 目录tests/e2e/e2e_test.go主 e2e 套件入口聚合 apps/device/rule 三个测试域tests/e2e_keadm/keadm_suite_test.go、tests/e2e_edgesite/edgesite_suite_test.gokeadm 与 edgesite 的独立套件入口tests/scripts/execute.sh、tests/scripts/compile.sh、tests/scripts/fast_test.sh安装 ginkgo CLI、ginkgo build编译、ginkgo -v xxx.test --透传参数运行的完整脚本链路。小结以 Ginkgo v2 官方 README 为主线可以得出Ginkgo 的价值在于用Describe/When/ContextBeforeEach/It的容器化 DSL 组织意图清晰的 spec用SpecContext与SpecTimeout保证异步场景可控用标签与命令行过滤器管理膨胀的套件用ginkgoCLI 与ginkgo -p/ginkgo watch覆盖构建、并行、剖析与快速反馈全流程Gomega 则补齐了同步/异步混用的断言表达力。在 KubeEdge 仓库中这套能力被 v2.21.0 版本完整 vendor 进项目并通过 e2e 各套件入口与tests/scripts下的构建/执行脚本落为一条装 CLI → 编译套件 → 拉起 kind 集群 → 透传 flag 运行 → 收集结果并清理的可复现端到端测试流水线。掌握以上内容后即可读懂并扩展 KubeEdge 现有的任何 Ginkgo 套件或为新的测试模块按同一模式搭建入口与执行脚本。【免费下载链接】kubeedgeKubernetes Native Edge Computing Framework (project under CNCF)项目地址: https://gitcode.com/GitHub_Trending/ku/kubeedge创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表