【问题标题】:ModuleNotFoundError when using mock.patch()使用 mock.patch() 时出现 ModuleNotFoundError
【发布时间】:2022-01-01 09:19:22
【问题描述】:

我想模拟来自 Python Kubernetes 客户端的响应。下面是我的 Kubernetes 服务的代码:

import os

from kubernetes.client.rest import ApiException
from kubernetes import client
from kubernetes.config import load_config
from exceptions.logs_not_found_exceptions import LogsNotFound
import logging

log = logging.getLogger("services/kubernetes_service.py")


class KubernetesService:
    def __init__(self):
        super().__init__()
        if os.getenv("DISABLE_KUBERNETES_CONFIG") == "False":
            load_config()

        self.api_instance = client.CoreV1Api()

    def get_namespaces(self):
        try:
            api_response = self.api_instance.list_namespace()
            dict_response = api_response.to_dict()

            namespaces = []
            for item in dict_response['items']:
                namespaces.append(item['metadata']['name'])

            log.info(f"Retrieved the namespaces: {namespaces}")
            return namespaces
        except ApiException as e:
            raise e

当我想使用 mock.patch 模拟这个时,我得到了一个 ModuleNotFoundError。下面是我的测试类的代码

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()
        print(self.service.api_instance)
        with mock.patch('services.kubernetes_service.KubernetesService.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']

当我将mock.patch 中的路径从services.kubernetes_service.KubernetesService.api_instance.list_namespace 编辑为services.kubernetes_service.KubernetesService.get_namespaces 时,它成功模拟了我输入的返回值。但我想模拟KubernetesService 类中self.api_instance.list_namespace() 行的响应。

有人出主意吗?

【问题讨论】:

  • 这不起作用,因为您要修补实例变量,而不是类属性。由于您已经拥有该实例,因此您可以改用 patch.object,例如 mock.patch.object(self.service.api_instance, 'list_namespace')
  • 嗨@MrBeanBremen 你能用你的解决方案发布答案​​吗?

标签: python unit-testing kubernetes mocking python-unittest.mock


【解决方案1】:

在您的示例中,您尝试修补类的实例属性 (api_instance)。这不能通过仅从类中引用来完成,因为它不是类属性 - 您需要一个实例。

模拟实例属性通常有两种标准方法:

  • 模拟整个类,在这种情况下,模拟类上的return_value 属性将是一个模拟,它替换该类的任何实例,因此可用于模拟实例属性
  • 使用 mock.patch.object 或类似方法模拟具体实例 - 这要求您可以访问测试中的实例

在你的情况下,模拟整个类不是一个选项,因为你需要使用类的功能,但是你可以通过self.service访问实例,你可以使用patch.object

    def test_get_namespaces(self):
        self.service = KubernetesService()
        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']

【讨论】:

    猜你喜欢
    • 2021-03-30
    • 2020-08-03
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 2022-12-17
    • 2021-12-25
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多