为运行在Kubernetes中的rest映射器创建假数据



我可以在提供kubecconfig时运行以下代码。这样我就可以得到gr的值:

func (o *ApplyOptions) RestMapper() (meta.RESTMapper, error) {
gr, err := restmapper.GetAPIGroupResources(o.discoveryClient)
if err != nil {
return nil, err
}
mapper := restmapper.NewDiscoveryRESTMapper(gr)
return mapper, nil
}

那么我已经启动了以下代码:

var kubeconfig *string
kubeconfig = flag.String("kubeconfig", filepath.Join(home, ".kube", "config"), "(optional) absolute path to the kubeconfig file")
flag.Parse()
// use the current context in kubeconfig
config, err := clientcmd.BuildConfigFromFlags("", *kubeconfig)
if err != nil {
panic(err.Error())
}
dynamicClient, err := dynamic.NewForConfig(config)
if err != nil {
panic(err.Error())
}
discoveryClient, err := discovery.NewDiscoveryClientForConfig(config)
if err != nil {
panic(err.Error())
}
applyOptions := apply.NewApplyOptions(dynamicClient, discoveryClient)
if err := applyOptions.Apply(context.Background(), []byte(applyStr)); err != nil {
log.Fatalf("apply error: %v", err)
}

现在我用它进行单元测试gr是空的(从restmapper.GetAPIGroupResources(o.discoveryClient))上面调试时,我怎么能添加一些假的,使它的工作也从测试?

var _ = DescribeTable(“test”, func(applyOptions *ApplyOptions, filename string, isExpectedErr bool, expectedErrMsg string) {

applyOptions = ApplyOptions{
discoveryClient: clientset.Discovery() ,
//discoveryClient: &k8sfake.Clientset,
dynamicClient:   dynamicfake.NewSimpleDynamicClient(runtime.NewScheme()),
}
// Here I need to initiate some fake data
restmapper, err := applyOptions.RestMapper()
if err != nil {
Fail(err.Error())
}

得到的错误是"k8s.io/apimachinery/pkg/api/**meta.NoKindMatchError**"

说明一下:我试图用kind: deployment为这个函数创建一个单元测试,我得到了上面的错误。

一种可能的方法是将restmapper抽象掉,这将使ApplyOptions依赖于抽象,因此您可以模拟它。假设您正在进行单元测试。

我们可以称之为RESTMapperDiscovery,这种类型将封装ApplyOptions使用的restmapper功能。它基本上是一个包装器。

type RESTMapperDiscovery struct {}
func (RESTMapperDiscovery) FromGroupResources(cl discovery.DiscoveryInterface) (meta.RESTMapper, error)

FromGroupResources将具体实现func (o *ApplyOptions) RestMapper()当前部分的代码。

要实现多态性,我们只需要一个接口。

type DiscoveryRESTMapper interface {
FromGroupResources(cl discovery.DiscoveryInterface) (meta.RESTMapper, error)
}

在这个阶段ApplyOptions也将依赖于DiscoveryRESTMapper

type ApplyOptions struct {
//... other fields
restMapper DiscoveryRESTMapper
}
func (o *ApplyOptions) RestMapper() (meta.RESTMapper, error) {
return o.restMapper.FromGroupResources(o.discoveryClient)
}

在测试时,您可以使用满足该接口并返回一些假数据的类型。meta.RESTMapper也是一个接口,因此你的假数据必须实现。

type mockRESTMapper struct {}
func (mockRESTMapper) FromGroupResources(cl discovery.DiscoveryInterface) (meta.RESTMapper, error) {
// return the fake meta.RESTMapper
}
applyOptions = &ApplyOptions{
discoveryClient: clientset.Discovery() ,
dynamicClient:   dynamicfake.NewSimpleDynamicClient(runtime.NewScheme()),
restMapper: mockRESTMapper{},
}
// here you have the fake data
restmapper, err := applyOptions.RestMapper()
if err != nil {
Fail(err.Error())
}

这种方法依赖于组合和接口来解耦外部依赖。k8的api与restmapper似乎依赖于相同的机制,因此您也可以从ApplyOptions的当前依赖项中模拟所有这些。这里的权衡是您的解决方案与k8s api紧密耦合,这可能导致与restmapper版本的中断更改和/或维护负担。

最新更新