如何在本地为 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 都是测试数据,无需对应真实资源。如果以后函数增加了预测、更新或查询等操作,还需要模拟相应的方法及其返回值。
备注:内容仅供参考。
