实践 Fake ClientSet 单元测试

简介: 在 Kubernetes 相关的开发中,client-go 是最常用的,对于 client-go 相关的代码我们可以通过 fake ClientSet 来编写单元测试,本文将实践利用 fake ClientSet

目录

什么是 ClientSet

实践环节


什么是 ClientSet

ClientSet顾名思义,就是一堆 Client 的集合。

在 client-go 中,ClientSet 声明了对于 Kubernetes 内置资源的操作接口的集合,代码位于 kubernetes/client-go


Fake ClientSet 顾名思义就是 “假” 的 Client 集合,实现了 ClientSet的接口,可以对 client-go 的代码进行模拟操作,可直接用于业务代码的单元测试,代码在 kubneretes/client-go 中。


实践环节

接下来我们将实际操作一下常见的几种 fake clientset 的用法


我们构造一个简单的场景,比如我们在业务逻辑中需要对 Node 进行更新标签的操作,逻辑如下:

import (
"context"metav1"k8s.io/apimachinery/pkg/apis/meta/v1""k8s.io/client-go/kubernetes")
funcLabelNode(ctxcontext.Context, cskubernetes.Interface, nodeNamestring, labelsmap[string]string) error {
node, err :=cs.CoreV1().Nodes().Get(ctx, nodeName, metav1.GetOptions{})
iferr!=nil {
returnerr    }
for_, l :=rangelabels {
node.Labels[l] =labels[l]
    }
_, err=cs.CoreV1().Nodes().Update(ctx, node, metav1.UpdateOptions{})
iferr!=nil {
returnerr    }
returnnil}


其中 kubernetes.Interface 就是 ClientSet实现的标准接口,比如常见的通过 ~/.kube/config加载 restConfig 再创建 ClientSet,得到的ClientSet就实现了 kubernetes.Interface

rc, err :=clientcmd.BuildConfigFromFlags("", "~/.kube/config")
iferr!=nil {
panic(err)
}
cs, err :=kubernetes.NewForConfig(rc)
iferr!=nil {
panic(err)
}


接下来我们编写上述逻辑的单元测试,首先我们先来看一下完整的代码

提示:

这里只做简单单元测试的演示,并不涉及到单元测试结构的合理性

packagenodesimport (
"testing""reflect""context"corev1"k8s.io/api/core/v1"metav1"k8s.io/apimachinery/pkg/apis/meta/v1"fakeclientset"k8s.io/client-go/kubernetes/fake")
funcTest_LabelNode(t*testing.T) {
cs :=fakeclientset.NewSimpleClientset(&corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "fake-node-1",
Labels: map[string]string{
"fake.label.kubernetes.io": "fake",
   },
    },
 })
newLabels :=map[string]string{
"fake.label.kubernetes.io": "new-value",
 }
err :=LabelNode(context.Background(), cs, "fake-node-1", newLabels)
iferr!=nil {
t.Error(err)
return }
got, err :=cs.CoreV1().Nodes().Get(context.Background(), "fake-node-1", metav1.GetOptions{})
iferr!=nil {
t.Error(err)
return }
if!reflect.DeepEqual(got.Labels, newLabels) {
t.Error(err)
return }
}


可以通过 NewSimpleClientset来生成 fake clientSet,这里的入参是 objects ...runtime.Object,其中 runtime.Object接口是 Kubernetes 资源都会实现的接口,也就是我们需要传入期望可以进行 CRUD 的假资源对象列表。


提示:

这里 runtime.Object不仅限于内置资源外,自定义资源也可以

cs :=fakeclientset.NewSimpleClientset(&corev1.Node{
ObjectMeta: metav1.ObjectMeta{
Name: "fake-node-1",
Labels: map[string]string{
"fake.label.kubernetes.io": "fake",
        },
    },
})


获取到 ClientSet后,我们可以将 Client 作为入参传入到逻辑中,并且按照业务逻辑传入需要更新的 Labels

newLabels :=map[string]string{
"fake.label.kubernetes.io": "new-value",
}
err :=LabelNode(context.Background(), cs, "fake-node-1", newLabels)
iferr!=nil {
t.Error(err)
return}

此时我们再通过这个 ClientSet去调用,获取的资源就是经过逻辑处理后的了,通过 reflect.DeepEqual 进行比较。

同样的,如果我们在处理逻辑中对初始化时传入的资源进行了 Delete等操作,资源同样会被销毁掉。


在我们对 Kubernetes 资源的操作中,fakeClient 有些逻辑操作是无法实现的,比如对于 fieldSelector 的筛选,是不支持的,详细可以参考这个 isuue:https://github.com/kubernetes/kubernetes/issues/78824


如下逻辑中,如果对 DeploymentList 通过 fakeClient 进行过滤,无法生效, labelSelector 是可以的。

// parse field selectordefaultSelector := []string{
fmt.Sprintf("metadata.namespace!=%s", metav1.NamespaceDefault),
fmt.Sprintf("metadata.namespace!=%s", metav1.NamespaceSystem),
}
fieldSelector, err :=fields.ParseSelector(strings.Join(defaultSelector, ","))
iferr!=nil {
returnnil, nil, err}
options.FieldSelector=fieldSelector.String()
deployList, err :=d.cs.AppsV1().Deployments(metav1.NamespaceNone).List(context.Background(), options)
iferr!=nil {
returnnil, nil, err}


除了上述我们提到的NewSimpleClientset,快速创建一个 FakeClient,还可以通过添加 AddReactor 来对 action 进行判断,增加更详细的判断逻辑, 比如如下案例:

cs :=&fakeclientset.Clientset{}
cs.AddReactor("*", "deployments", func(actionclientgotesting.Action) (handledbool, retruntime.Object, errerror) {
returntrue, &appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{
Name:      name,
Namespace: namespace,
        },
Spec: appsv1.DeploymentSpec{
Selector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"app": "busybox",
                },
            },
Template: corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{
"app": "busybox",
                    },
                },
Spec: corev1.PodSpec{
Containers: []corev1.Container{
                        {
Name:  "container-1",
Image: "busybox",
                        },
                    },
                },
            },
        },
    }, nil})


相关链接:

相关实践学习
容器服务Serverless版ACK Serverless 快速入门:在线魔方应用部署和监控
通过本实验,您将了解到容器服务Serverless版ACK Serverless 的基本产品能力,即可以实现快速部署一个在线魔方应用,并借助阿里云容器服务成熟的产品生态,实现在线应用的企业级监控,提升应用稳定性。
云原生实践公开课
课程大纲 开篇:如何学习并实践云原生技术 基础篇: 5 步上手 Kubernetes 进阶篇:生产环境下的 K8s 实践 相关的阿里云产品:容器服务 ACK 容器服务 Kubernetes 版(简称 ACK)提供高性能可伸缩的容器应用管理能力,支持企业级容器化应用的全生命周期管理。整合阿里云虚拟化、存储、网络和安全能力,打造云端最佳容器化应用运行环境。 了解产品详情: https://www.aliyun.com/product/kubernetes
目录
相关文章
|
2天前
|
IDE 测试技术 Go
【字节跳动青训营】后端笔记整理-3 | Go语言工程实践之测试
用于验证已经修改或新增功能后,软件的既有功能是否受到影响。
50 2
|
3天前
|
Java 测试技术 持续交付
Java中的异常处理机制探索自动化测试在微服务架构中的实践与挑战
【5月更文挑战第27天】本文将深入探讨Java中的异常处理机制,包括异常的概念、分类以及如何使用try-catch-finally语句进行异常处理。文章还将介绍自定义异常的方法以及在实际开发中如何选择合适的异常处理策略。 【5月更文挑战第27天】 随着软件开发领域向微服务架构的转型,传统的软件测试方法面临诸多挑战。本文旨在探讨自动化测试在微服务环境下的应用实践及所面临的问题。我们将从微服务的特性出发,分析自动化测试的必要性,并深入讨论如何构建一个高效、鲁棒的自动化测试框架。文章还将介绍一系列创新的测试策略和工具选择,以及如何克服微服务带来的分布式复杂性。最后,通过案例研究,展示自动化测试在实
|
3天前
|
设计模式 敏捷开发 监控
深入探究软件自动化测试的策略与实践深入理解PHP中的命名空间
【5月更文挑战第27天】 在软件开发周期中,确保代码质量是至关重要的一环。随着敏捷开发和持续集成的普及,自动化测试成为提升效率和保障软件质量的重要手段。本文将详细探讨自动化测试策略的制定、工具选择以及在实际项目中的执行过程。我们将从自动化测试的基本原则出发,分析不同类型和级别的自动化测试案例,并结合具体实例,讨论如何优化测试流程,减少冗余,提高测试覆盖率和准确性。通过阅读本文,读者将获得一套实用的自动化测试实施框架,以支持其在快速迭代的开发环境中维护高水平的软件品质。 【5月更文挑战第27天】在本文中,我们将探讨PHP中的命名空间(namespace)的概念、用途和实现方式。通过详细解释命名
|
3天前
|
运维 监控 Linux
提升系统稳定性:Linux服务器性能监控与故障排查实践深入理解与实践:持续集成在软件测试中的应用
【5月更文挑战第27天】在互联网服务日益增长的今天,保障Linux服务器的性能和稳定性对于企业运维至关重要。本文将详细探讨Linux服务器性能监控的工具选择、故障排查流程以及优化策略,旨在帮助运维人员快速定位问题并提升系统的整体运行效率。通过实际案例分析,我们将展示如何利用系统资源监控、日志分析和性能调优等手段,有效预防和解决服务器性能瓶颈。
|
3天前
|
机器学习/深度学习 敏捷开发 测试技术
深入理解自动化测试:框架选择与实践挑战利用机器学习技术优化数据中心冷却系统
【5月更文挑战第27天】 在现代软件开发周期中,自动化测试已成为确保产品质量和加快市场投放的关键步骤。本文深入探讨了自动化测试的框架选择问题,并剖析了实施过程中面临的挑战及其解决方案。通过比较不同测试框架的特点,我们旨在为读者提供一套明确的指导原则,帮助他们根据项目需求做出恰当的技术决策。同时,文中还分享了实际案例和最佳实践,以期帮助开发团队克服实施自动化测试时可能遇到的障碍。
|
3天前
|
机器学习/深度学习 敏捷开发 测试技术
深入探索软件测试中的持续集成与持续部署(CI/CD)实践利用机器学习提升网络安全防御效能
【5月更文挑战第27天】 在现代软件开发的快节奏环境中,持续集成(Continuous Integration, CI)和持续部署(Continuous Deployment, CD)已成为确保产品质量和加快交付速度的关键策略。本文将深入探讨CI/CD在软件测试中的应用,分析其对提高自动化测试效率、缩短反馈周期以及优化发布流程的重要性。通过实际案例研究,我们揭示了成功实施CI/CD的最佳实践,并讨论了面临的挑战及其解决方案。
|
3天前
|
安全 数据管理 测试技术
网络安全与信息安全:防范漏洞、加强加密与提升安全意识深入探索自动化测试框架的设计原则与实践应用化测试解决方案。文章不仅涵盖了框架选择的标准,还详细阐述了如何根据项目需求定制测试流程,以及如何利用持续集成工具实现测试的自动触发和结果反馈。最后,文中还将讨论测试数据管理、测试用例优化及团队协作等关键问题,为读者提供全面的自动化测试框架设计与实施指南。
【5月更文挑战第27天】 在数字化时代,网络安全与信息安全已成为维护国家安全、企业利益和个人隐私的重要环节。本文旨在分享关于网络安全漏洞的识别与防范、加密技术的应用以及提升安全意识的重要性。通过对这些方面的深入探讨,我们希望能为读者提供一些实用的建议和策略,以应对日益严峻的网络安全挑战。 【5月更文挑战第27天】 在软件开发周期中,自动化测试作为保障软件质量的关键步骤,其重要性日益凸显。本文旨在剖析自动化测试框架设计的核心原则,并结合具体案例探讨其在实际应用中的执行策略。通过对比分析不同测试框架的优缺点,我们提出一套高效、可扩展且易于维护的自动
|
3天前
|
设计模式 敏捷开发 监控
深入探索软件测试:自动化与性能优化实践
【5月更文挑战第27天】 在软件开发生命周期中,测试阶段是保障产品质量和用户体验的关键环节。随着敏捷开发和持续集成的理念深入人心,自动化测试已成为提升效率、确保可靠性的重要手段。本文将深入探讨自动化测试的最佳实践,并结合性能优化策略,旨在为读者提供一套全面提升软件测试效能的技术方案。通过分析现代软件测试的挑战与机遇,我们将揭示如何有效整合自动化工具、框架选择、脚本开发、以及持续监控等多维度因素,打造一个高效、稳定的测试环境。
|
3天前
|
搜索推荐 测试技术 UED
软件测试的艺术:从理论到实践的探索之旅
本文深入探讨了软件测试的核心理念、方法论及其在现代软件开发中的应用。通过分析测试的不同阶段和类型,文章揭示了如何有效地识别和解决软件缺陷,确保产品质量。同时,本文还提供了实际案例分析,展示了测试策略在实际项目中的应用效果,旨在帮助读者全面理解软件测试的重要性和复杂性。
|
3天前
|
敏捷开发 监控 Java
深入理解自动化测试:框架选择与实践
【5月更文挑战第27天】在软件开发的快速迭代过程中,自动化测试已成为提升效率、确保质量的重要手段。本文将探讨自动化测试框架的选择标准及其在实际项目中的应用情况,以帮助读者更好地理解自动化测试的价值和实施策略。文中不仅涉及框架的功能对比,还结合案例分析,展示如何根据不同需求制定合适的自动化测试方案。