PAYATHON 2026

如何在本地为 Google Cloud 的现有资源编写功能测试?

技术老齐

可以用 Python 标准库中的 unittest.mock.Mock 创建 fake_endpoint,再显式设置它的 _gca_resource.name。这样无需创建真实的 Endpoint,也无需 GCP 项目访问权限。

为什么只模拟属性就够了?

当前的 my_function 只读取一条属性链:

existing_endpoint._gca_resource.name

测试对象只要提供这条属性链,函数就能运行。Endpoint 类型注解不会在 Python 运行时强制检查参数类型。

这个测试只验证函数读取并返回资源名称的逻辑,通常属于单元测试。它无法验证云端资源是否存在、IAM 权限是否有效,或 Google Cloud API 是否可用。

使用 Mock 编写本地测试

将以下示例保存为 test_my_function.py:

from unittest.mock import Mock

from google.cloud.aiplatform import Endpoint


def my_function(existing_endpoint: Endpoint) -> str:
    return existing_endpoint._gca_resource.name


def test_my_function_should_work():
    expected_name = (
        "projects/12345/locations/europe-west1/endpoints/12345"
    )

    fake_endpoint = Mock(spec=Endpoint)
    fake_endpoint._gca_resource = Mock()
    fake_endpoint._gca_resource.name = expected_name

    assert my_function(fake_endpoint) == expected_name

在已安装 google-cloud-aiplatform 和 pytest 的环境中运行:

python -m pytest test_my_function.py

Mock(spec=Endpoint) 以 Endpoint 类作为模拟对象的接口参考,不会调用 Endpoint(...) 构造函数。这里显式设置了 _gca_resource,无需依赖 Mock 能否从类本身发现该属性。spec 会限制属性访问,但不会完整模拟 SDK 的行为,具体机制见 Python Mock 文档。

实际项目中,测试文件应从业务模块导入 my_function,避免在测试里复制函数实现。

注意 Mock 的 name 参数

不要用下面的写法设置资源名称:

resource = Mock(name=expected_name)

Mock 构造函数的 name 参数设置的是模拟对象的调试名称,不会将该字符串赋给 resource.name。要设置资源名称,应在创建对象后赋值:

resource = Mock()
resource.name = expected_name

关于这个参数与同名属性的区别,参见 name 属性说明。

如果可以修改函数,优先使用公开属性

_gca_resource 是 SDK 内部属性,直接使用它会让业务代码依赖 SDK 的内部实现。Endpoint 的公开属性 resource_name 可用于获取完整资源名称,见 Endpoint API 文档。

如果所用 SDK 版本提供该属性,可以将函数和测试一起改为:

def my_function(existing_endpoint: Endpoint) -> str:
    return existing_endpoint.resource_name


def test_my_function_should_work():
    expected_name = (
        "projects/12345/locations/europe-west1/endpoints/12345"
    )
    fake_endpoint = Mock(spec=Endpoint)
    fake_endpoint.resource_name = expected_name

    assert my_function(fake_endpoint) == expected_name

示例中的项目、区域和 Endpoint ID 都是测试数据,无需对应真实资源。如果以后函数增加了预测、更新或查询等操作,还需要模拟相应的方法及其返回值。

备注:内容仅供参考。