You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何mock K8s runtime.Object与Encoder为GetModified函数编写单元测试

两种方案实现入参模拟

方案1:使用K8s原生对象+官方Codec(最简便,推荐)

你不需要自己手写mock,K8s官方提供的核心资源对象(比如Pod、ConfigMap)本身就实现了runtime.Object接口,官方也有现成的runtime.Encoder实现,直接用即可,测试逻辑更贴合实际使用场景。

所需依赖导入

import (
    corev1 "k8s.io/api/core/v1"
    metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    "k8s.io/apimachinery/pkg/runtime"
    "k8s.io/apimachinery/pkg/runtime/serializer/json"
)

测试参数构造示例

// 1. 构造测试用runtime.Object:这里用最简单的ConfigMap为例
testObj := &corev1.ConfigMap{
    ObjectMeta: metav1.ObjectMeta{
        Name: "test-cm",
        Annotations: map[string]string{
            corev1.LastAppliedConfigAnnotation: `{"apiVersion":"v1","kind":"ConfigMap","metadata":{"name":"test-cm"},"data":{"foo":"bar"}}`,
            "other-anno": "test-value",
        },
    },
    Data: map[string]string{
        "foo": "bar",
    },
}

// 2. 构造测试用runtime.Encoder:用官方JSON序列化器
scheme := runtime.NewScheme()
_ = corev1.AddToScheme(scheme)
codec := json.NewSerializerWithOptions(json.DefaultMetaFactory, scheme, scheme, json.SerializerOptions{Pretty: false})

补全后的完整测试代码

把上面的参数填入你的测试用例即可,示例:

func TestGetModified(t *testing.T) {
    // 预先构造公共测试资源
    scheme := runtime.NewScheme()
    _ = corev1.AddToScheme(scheme)
    codec := json.NewSerializerWithOptions(json.DefaultMetaFactory, scheme, scheme, json.SerializerOptions{Pretty: false})

    testCMWithoutAnno := &corev1.ConfigMap{
        ObjectMeta: metav1.ObjectMeta{Name: "test-cm-1"},
        Data: map[string]string{"foo": "bar"},
    }
    testCMWithAnno := &corev1.ConfigMap{
        ObjectMeta: metav1.ObjectMeta{
            Name: "test-cm-2",
            Annotations: map[string]string{
                corev1.LastAppliedConfigAnnotation: "old-config",
            },
        },
        Data: map[string]string{"foo": "new-bar"},
    }

    type args struct {
        obj      runtime.Object
        annotate bool
        codec    runtime.Encoder
    }
    tests := []struct {
        name    string
        args    args
        wantErr bool
    }{
        {
            name: "无注解+不开启annotate",
            args: args{
                obj:      testCMWithoutAnno.DeepCopyObject(),
                annotate: false,
                codec:    codec,
            },
            wantErr: false,
        },
        {
            name: "有原始注解+开启annotate",
            args: args{
                obj:      testCMWithAnno.DeepCopyObject(),
                annotate: true,
                codec:    codec,
            },
            wantErr: false,
        },
    }
    for _, tt := range tests {
        t.Run(tt.name, func(t *testing.T) {
            got, err := GetModified(tt.args.obj, tt.args.annotate, tt.args.codec)
            if (err != nil) != tt.wantErr {
                t.Errorf("GetModified() error = %v, wantErr %v", err, tt.wantErr)
                return
            }
            if err == nil && len(got) == 0 {
                t.Error("GetModified()返回空字节数组")
            }
            // 可额外断言返回的字节数组里包含预期的字段,比如Data的内容
        })
    }
}

方案2:纯Mock接口实现(无额外依赖)

如果你需要完全隔离K8s资源依赖,可以用mock工具(比如gomock)生成runtime.Object和runtime.Encoder的mock实现,手动打桩方法返回值即可:

  • runtime.Object需要实现的方法很少,你也可以手写一个结构体实现接口,只需要满足metadataAccessor的调用要求即可,重点实现Annotations、SetAnnotations相关的逻辑。
  • runtime.Encoder只需要实现Encode方法,返回固定的测试字节数组即可。

内容的提问来源于stack exchange,提问作者Jenney

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 14:36:02