ginkgo 学习笔记

参考文章

(kubebuilder如何写测试用例)https://book.kubebuilder.io/cronjob-tutorial/writing-tests
(ginkgo和gomega学习笔记)https://blog.gmem.cc/ginkgo-study-note

常用测试方法

TDD 测试驱动开发

执行test → 失败 → coding → 执行test → 成功

BDD 行为驱动开发

TDD 侧重点偏向开发,通过测试用例来规范约束开发者编写出质量更高、bug更少的代码。而BDD更加侧重设计,其要求在设计测试用例时对系统进行定义,倡导使用通用的语言将系统的行为描述出来,将系统设计和测试用例结合起来,以此为驱动进行开发工作。BDD 衍生于 TDD,主要区别就是在于测试的描述上。BDD 使用一种更通俗易懂的文字来描述测试用例,更关注需求的功能,而不是实际结果。BDD 赋予的像阅读句子一样阅读测试的能力带来对测试认知上的转变,有助于我们去考虑如何更好写测试。

一句话理解 Ginkgo是测试框架  gomega 是Ginkgo首选断言库。

Ginkgo

描述功能

Describe来定义测试套件,Context来分组测试,并且在每个It块里,我们编写一个实际的测试,表达了当满足某个条件(“when …”)应该发生什么(“should …”)。

当我们使用 “Describe” 时,我们实际上在说,”以下是我将要描述的一系列测试场景和测试用例”

常用的关键字有

It 是测试例的基本单位,即It包含的代码就算一个测试用例
Context 和Describe的功能都是将一个或多个测试例归类
BeforeEach 是每个测试例执行前执行该段代码
AfterEach 是每个测试例执行后执行该段代码
JustBeforeEach 是在BeforeEach执行之后,测试例执行之前执行
BeforeSuite 是在该测试集执行前执行,即该文件夹内的测试例执行之前
AfterSuite 是在该测试集执行后执行,即该文件夹内的测试例执行完后
By 是打印信息,内容只能是字符串,只会在测试例失败后打印,一般用于调试和定位问题
Fail 是标志该测试例运行结果为失败,并打印里面的信息
还有一个 Specify 和 It 功能完全一样, It 属于其简写

gomega

Eventually 用于你期望某个条件最终将为真,但是可能需要一些时间去达到。例如,如果你正在等待一个异步操作的结果,那么你可以使用Eventually来持续检查直到该条件满足或者超过了一个超时时限。它对处理可能有延迟的操作或者某些可能需要多次尝试才能成功的操作非常有用。(阻塞并轮询,直到能通过断言)
Consistently 用于确保某个条件在给定的一段时间内始终为真。它会在一段时间内多次检查该条件是否满足,如果有任何一个检查失败,那么断言就会失败。它通常用于确保系统的一个状态不会因为异步事件或者其他原因而改变。(检查断言是否在一定时间段内总是通过)

暂时用到这两个 后面慢慢积累

使用方式

ginkgo -r -v

-r: 递归查找test文件
-v: 输出详细信息

开发流程

kubebuilder 会自动生成好 suite_test.go测试套件
       1. 将 envtest 集群配置为从 CRD 目录 Kubebuilder 脚手架中读取 CRD。
       2. 使用 envtest 创建 k8s 控制层的测试环境 (api-server, etcd, kubectl)
       3. 默认是不会添加自定义的controller到测试集群需要手动添加下(需要开发)

以自定义controller为例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var _ = BeforeSuite(func() {
ctx, cancel = context.WithCancel(context.TODO()) // 主要注意添加context
...
k8sClient, err = client.New(cfg, client.Options{Scheme: scheme.Scheme})
Expect(err).NotTo(HaveOccurred())
Expect(k8sClient).NotTo(BeNil())

// Create a new manager to run the controller
k8sManager, err := ctrl.NewManager(cfg, ctrl.Options{
Scheme: scheme.Scheme,
})
Expect(err).ToNot(HaveOccurred())

// Create a new test of the controller
err = (&TestReconciler{
Client: k8sManager.GetClient(),
Scheme: k8sManager.GetScheme(),
}).SetupWithManager(k8sManager)
Expect(err).ToNot(HaveOccurred())

// Start the manager
go func() {
defer GinkgoRecover()
err = k8sManager.Start(ctx) // The manager will run in the background
Expect(err).ToNot(HaveOccurred(), "failed to run manager")
}()

var _ = AfterSuite(func() {
cancel() // 测试完成后 清理controller
By("tearing down the test environment")
err := testEnv.Stop()
Expect(err).NotTo(HaveOccurred())
})

如何写测试用例(需要开发)

1
2
3
4
5
6
7
Describe("InstanceController", func() {  // 声明为虚拟机controller的测试用例
Context("When instance create", func() { //细分测试场景 声明为虚拟机创建后的测试用例
    It("测试用例", func(){ // 测试用例 虚拟机关机,开机等等
        ...
})
})
})