子类继承父类通用API请求函数的设计方案选型及测试策略咨询
这是个很棒的设计问题,核心其实是在代码简洁性和接口易用性/可维护性之间做权衡。咱们一步步拆解来看:
两种方案的优劣对比
方案1:维持当前通用调用方式
优点
- 类结构极致简洁,不用为每个资源写重复的封装代码
- 父类的通用逻辑只需要维护一次,改动成本低
缺点
- 接口不直观:调用者必须牢记每个资源对应的
endpoint和参数规则(比如isBot要传字符串"false"还是布尔值?参数名是驼峰还是下划线?),门槛高且容易出错 - 缺乏类型安全:参数用
Dict传递,IDE没法自动提示合法参数,编译期也没法校验错误 - 耦合性高:调用代码和底层API细节强绑定,一旦API的端点或参数规则变更,所有调用处都要同步修改
方案2:子类封装专属方法(更推荐)
优点
- 接口语义清晰:
user_manager.get_users(is_bot=False)一眼就能看懂用途,不需要额外查API文档 - 类型安全与自动提示:方法参数明确,IDE能自动补全,还能通过类型注解(比如
is_bot: bool)强制校验参数类型,避免传错值(比如把布尔值误传成字符串) - 解耦API细节:如果API的端点或参数规则变了(比如
isBot改成is_bot),只需要修改UserManager.get_users()一处,所有调用方不受影响 - 可扩展性强:后续可以在专属方法里加额外逻辑,比如对返回数据做预处理、添加缓存,或者设置业务相关的默认参数,完全不影响父类的通用逻辑
优化后的示例代码
可以给专属方法加上类型注解,让代码更健壮:
from typing import List from your_module import OMDManager, User # 假设User是返回的资源实体类 class UserManager(OMDManager): def get_users(self, limit: int = 100, is_bot: bool = False) -> List[User]: params = {"isBot": str(is_bot).lower(), "limit": limit} # 这里可以添加预处理、缓存等业务逻辑 raw_user_data = self.get_omd_assets(endpoint="/users", params=params) # 把原始字典转成实体类,方便上层调用 return [User(**user) for user in raw_user_data]
关于测试的问题
已经测试过get_omd_assets(),还需要测试子类的专属方法吗?答案是需要,但可以轻量化处理:
- 不需要重复测试父类的核心逻辑:比如API请求、分页这些,父类测试已经覆盖,不用再做冗余测试
- 需要聚焦测试专属方法的特有逻辑:
- 参数映射是否正确:比如
is_bot=True是否转成了API要求的{"isBot": "true"} - 端点是否传对:比如调用
get_users()是否确实用了/users端点 - 返回值处理(如果有):比如是否正确把原始数据转成了
User实体类 - 默认参数是否生效:比如不传
limit时是否用了默认值100
- 参数映射是否正确:比如
轻量化测试示例(用pytest)
def test_user_manager_get_users(mocker): # 模拟父类的get_omd_assets方法,捕获传入的参数 mock_get_assets = mocker.patch.object(OMDManager, "get_omd_assets") mock_get_assets.return_value = [{"id": 1, "name": "Alice"}] user_manager = UserManager(mock_client) users = user_manager.get_users(limit=50, is_bot=True) # 验证端点和参数是否正确传递 mock_get_assets.assert_called_once_with( endpoint="/users", params={"isBot": "true", "limit": 50} ) # 验证返回值是否正确转成了User对象 assert len(users) == 1 assert users[0].id == 1 assert users[0].name == "Alice"
总结
如果你的项目是小型临时脚本、或者调用方都是熟悉API细节的内部开发者,维持当前方案也能接受。但如果是团队协作项目、需要长期维护的代码,或者要对外提供SDK,强烈推荐子类封装专属方法——它带来的接口易用性、可维护性提升,远大于多写几行封装代码的成本。
内容的提问来源于stack exchange,提问作者PretendNotToSuck
相关产品推荐
相关产品推荐

