使用mock.patch模拟Kubernetes客户端返回值出现ModuleNotFoundError如何解决
解决方案
错误原因
你使用的mock路径services.kubernetes_service.KubernetesService.api_instance.list_namespace不存在:api_instance是KubernetesService类实例化过程中才会绑定到实例上的动态属性,不属于类的静态属性,mock无法通过类路径直接定位到该方法,因此触发ModuleNotFoundError。
你之前mockget_namespaces成功,是因为该方法是类定义时就存在的成员方法,路径合法,但这种mock会跳过整个get_namespaces的内部逻辑,无法验证你代码里对返回值的解析处理是否正确。
修复方案
方案1:直接mock已实例化对象的对应方法(最推荐)
你在测试用例中已经提前生成了KubernetesService的实例self.service,直接用mock.patch.object针对该实例的api_instance的list_namespace方法做mock即可,不需要处理复杂的路径匹配:
import os from unittest import mock from tests.unit_tests import utils from services.kubernetes_service import KubernetesService class TestKubernetesService: @mock.patch.dict(os.environ, {"DISABLE_KUBERNETES_CONFIG": "True"}) def test_get_namespaces(self): self.service = KubernetesService() # 直接针对当前实例的api_instance的list_namespace方法mock with mock.patch.object( self.service.api_instance, "list_namespace", return_value=utils.kubernetes_namespaces_response() ): actual_result = self.service.get_namespaces() assert actual_result == ['default', 'kube-node-lease', 'kube-public', 'kube-system']
方案2:mock CoreV1Api类的原生list_namespace方法
因为self.api_instance本质是kubernetes.client.CoreV1Api的实例,你也可以直接mock该类的对应方法,适合需要批量mock所有CoreV1Api实例调用的场景:
import os from unittest import mock from tests.unit_tests import utils from services.kubernetes_service import KubernetesService class TestKubernetesService: @mock.patch.dict(os.environ, {"DISABLE_KUBERNETES_CONFIG": "True"}) @mock.patch("kubernetes.client.CoreV1Api.list_namespace") def test_get_namespaces(self, mock_list_namespace): mock_list_namespace.return_value = utils.kubernetes_namespaces_response() self.service = KubernetesService() actual_result = self.service.get_namespaces() assert actual_result == ['default', 'kube-node-lease', 'kube-public', 'kube-system']
注意:你需要保证
utils.kubernetes_namespaces_response()返回的对象实现了to_dict()方法,返回结构和真实k8s客户端返回的V1NamespaceList的to_dict()结果一致,否则会触发属性错误。
内容的提问来源于stack exchange,提问作者Lucas Scheepers
相关产品推荐
相关产品推荐

