使用Fabric8访问OpenShift CustomResource时如何编写Mock Junit测试
实现思路与示例代码
以下基于JUnit 5 + Mockito框架实现三类对象的Mock,可直接适配你现有的业务代码:
前置依赖
Maven项目需引入如下测试依赖:
<dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>4.11.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>4.11.0</version> <scope>test</scope> </dependency> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter-api</artifactId> <version>5.9.2</version> <scope>test</scope> </dependency>
Mock逻辑说明
- Mock
KubernetesClient:直接Mock接口即可,无需实例化真实的DefaultKubernetesClient - Mock
MixedOperation:Mock对应泛型类型的MixedOperation对象,配置链式调用的返回规则:inNamespace()返回自身,withName()返回Mock的Resource对象 - Mock
CertificateRequest:直接构造或Mock该CRD类,按需设置元数据、spec等属性作为查询返回值
注意:建议你对原有业务代码做小改造,将KubernetesClient实例化逻辑抽离,通过方法入参或依赖注入的方式传入,避免直接在方法内new DefaultKubernetesClient,否则需要额外引入PowerMock才能Mock构造方法,不推荐这种方式。
完整测试示例
以测试你提供的业务逻辑为例,测试覆盖CertificateRequest存在和不存在两种场景:
import io.fabric8.kubernetes.api.model.KubernetesResourceList; import io.fabric8.kubernetes.client.KubernetesClient; import io.fabric8.kubernetes.client.MixedOperation; import io.fabric8.kubernetes.client.Resource; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) public class CertificateRequestServiceTest { @Mock private KubernetesClient k8sClient; @Mock private MixedOperation<CertificateRequest, KubernetesResourceList<CertificateRequest>, Resource<CertificateRequest>> certClient; @Mock private Resource<CertificateRequest> certResource; @Mock private CertificateRequest mockCertificateRequest; // 测试场景:CertificateRequest已存在,验证delete方法被调用 @Test void testCertRequestExists() { // 配置Mock规则 when(k8sClient.resources(CertificateRequest.class)).thenReturn(certClient); when(certClient.inNamespace(anyString())).thenReturn(certClient); when(certClient.withName(anyString())).thenReturn(certResource); when(certResource.get()).thenReturn(mockCertificateRequest); // 调用你的业务方法,将Mock的k8sClient传入 yourBusinessMethod(k8sClient, "test-namespace", "test-cert-request"); // 验证delete方法执行了1次 verify(certResource, times(1)).delete(); } // 测试场景:CertificateRequest不存在,验证delete方法未被调用 @Test void testCertRequestNotExists() { // 配置Mock规则 when(k8sClient.resources(CertificateRequest.class)).thenReturn(certClient); when(certClient.inNamespace(anyString())).thenReturn(certClient); when(certClient.withName(anyString())).thenReturn(certResource); when(certResource.get()).thenReturn(null); // 调用你的业务方法,将Mock的k8sClient传入 yourBusinessMethod(k8sClient, "test-namespace", "test-cert-request"); // 验证delete方法未执行 verify(certResource, never()).delete(); } // 这是你改造后的业务方法,将k8sClient作为入参传入 private void yourBusinessMethod(KubernetesClient k8sClient, String certNamespce, String certRequestName) { try (KubernetesClient client = k8sClient) { MixedOperation< CertificateRequest, KubernetesResourceList<CertificateRequest>, Resource<CertificateRequest>> certClient = client.resources(CertificateRequest.class); CertificateRequest certificateRequest = certClient.inNamespace(certNamespce).withName(certRequestName).get(); if (certificateRequest == null) { System.out.printf("CertificateRequest %s in certNamespce %s is a new one.%n", certRequestName, certNamespce); } else { certClient.inNamespace(certNamespce).withName(certRequestName).delete(); System.out.printf("Delete existing CertificateRequest %s in certNamespce %s, then create a new one.%n", certRequestName, certNamespce); } } catch (Exception exception) { System.err.println("Hit an error when create a CertificateRequest: " + exception); } } }
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

