在运行单元测试时注入 KubernetesClient 对象的模拟实例

问题描述 投票:0回答:1

在我的 Spring Boot 项目中,我使用库(作为依赖项)与 kubernetes 集群进行通信。库名称是fabric8-kubernetes-client,将其添加为依赖项:

implementation("io.fabric8:kubernetes-client:6.9.0")

我创建了一个配置类来服务

KubernetesClient
bean:

@Configuration
public class K8sClientConfig {
    @Bean
    public KubernetesClient kubernetesClient() {
        // it will establish a connection to a k8s cluster
        return new KubernetesClientBuilder().build();
    }
}

另一个

@Component
类通过构造函数上的自动装配注入上面的bean:

@Component
public class ProductManager {
    private KubernetesClient kubernetesClient;

    @Autowired
    public ProductManager(KubernetesClient kubernetesClient) {
        this.kubernetesClient = kubernetesClient;
    }


    
    public void createConfigMap() {
        // using the kubernetesClient to create ConfigMap in cluster, pseudo code for simplicity
        ConfigMap cm = ...;

        kubernetesClient.configMaps().resource(cm).create();
    }

    // I created this function only for my unit test to inject mocked instance of KubernetesClient, but I really don't like this way...
    public void setKubernetesClient(KubernetesClient client) {
         this.kubernetesClient = client
    }
}

运行应用程序时一切正常。

但是现在,我想编写一些单元测试,我真的想使用模拟的

KubernetesClient
,这样运行测试时就不需要真正的kubernetes连接了。

因此,我使用关联的 kubernetes-server-mock 依赖项:

testImplementation("io.fabric8:kubernetes-server-mock:6.9.0")

在我的测试类中,我创建了一个模拟的

KubernetesClient

@SpringBootTest
@EnableKubernetesMockClient(crud = true)
public class ProductManagerTest {

   // mocked instances, because of the annotation @EnableKubernetesMockClient, this is the way the library is suggesting for mocking
   private KubernetesClient kubernetesClient;
   private KubernetesMockServer server;

   @Autowired
   private ProductManager productManager;

   @BeforeEach
   public void beforeTest() {
      // inject mocked client using that ugly function before each test run
      productManager.setKubernetesClient(kubernetesClient);
   }

   @Test
   public void testCreateConfigMap() {
       createConfigMap();
       
       //assertion to check configMap is created
       ...
   }
  
}

上述单元测试如果能到达真实的kubernetes集群则运行良好。这就是我需要解决的问题,因为即使我使用模拟客户端并以“丑陋”的方式注入它(即

setKubernetesClient(...)
函数),但由于
@SpringBootTest
将加载所有bean,这意味着配置类
上面的K8sClientConfig
仍然执行
new KubernetesClientBuilder().build()
,它会寻找真正的连接。

我想知道是否可以有条件地注入

KubernetesClient
豆,例如:

@Configuration
public class K8sClientConfig {
    @Bean
    public KubernetesClient kubernetesClient() {
        if(NOT_RUNNING_TEST) {
            return new KubernetesClientBuilder().build();
        } else {
            // somehow create and return the mocked KubernetesClient
        }
        
    }
}

如果可能的话如何实现这一点?

如果上述想法不可行,其他更好的解决方案是什么?

spring-boot unit-testing kubernetes dependency-injection fabric8-kubernetes-client
1个回答
0
投票

谢谢你,你的问题实际上有一个我遗漏的部分(测试依赖项)

就我而言,这是帮助我正确模拟一切的设置:

@EnableKubernetesMockClient(crud = true)
class SampleClassTest {

    private KubernetesClient kubernetesClient;
    private KubernetesMockServer server;

    @BeforeEach
    public void beforeTest() {
        KubernetesClientBuilder kubernetesClientBuilder = mock(KubernetesClientBuilder.class);
        when(kubernetesClientBuilder.build()).thenReturn(kubernetesClient);
        SampleClass.setKubernetesClientBuilder(kubernetesClientBuilder);
    }
   } 

在我的例子中 SampleClass 是一个静态类,这就是为什么我不将它用作间谍。

© www.soinside.com 2019 - 2024. All rights reserved.