在我的 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
}
}
}
如果可能的话如何实现这一点?
如果上述想法不可行,其他更好的解决方案是什么?
谢谢你,你的问题实际上有一个我遗漏的部分(测试依赖项)
就我而言,这是帮助我正确模拟一切的设置:
@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 是一个静态类,这就是为什么我不将它用作间谍。