基于Mother Pattern优化VarCharType子类测试代码的最佳实践
解决方案
针对你遇到的两个问题,我们可以通过泛型通用Mother基类实现类型安全的复用,彻底解决长度同步和重复代码问题,完全不需要使用typing.Any。
步骤1:定义泛型基类封装通用逻辑
创建泛型的VarCharMother基类,自动读取目标VarCharType子类的长度限制,同时支持可配置字符集:
import random import string from typing import TypeVar, Generic, Type from your_module import VarCharType # 替换为实际模块路径 # 绑定到VarCharType子类的泛型变量,保证类型安全 T = TypeVar('T', bound=VarCharType) class VarCharMother(Generic[T]): # 子类必须指定目标类型 _target_type: Type[T] # 默认字符集,可被子类覆盖或调用时传入 _default_charset: str = string.ascii_uppercase @classmethod def _generate_string(cls, length: int, charset: str | None = None) -> str: """生成指定长度的随机字符串""" return ''.join(random.choices(charset or cls._default_charset, k=length)) @classmethod def random_min(cls, charset: str | None = None) -> T: """生成符合最小长度要求的随机实例""" return cls._target_type(cls._generate_string(cls._target_type._MIN_LENGTH, charset)) @classmethod def random_max(cls, charset: str | None = None) -> T: """生成符合最大长度要求的随机实例""" return cls._target_type(cls._generate_string(cls._target_type._MAX_LENGTH, charset)) @classmethod def random_with_length(cls, length: int, charset: str | None = None) -> T: """生成指定长度的合法随机实例(可选扩展)""" if not cls._target_type._MIN_LENGTH <= length <= cls._target_type._MAX_LENGTH: raise ValueError(f"Length {length} out of bounds for {cls._target_type.__name__}") return cls._target_type(cls._generate_string(length, charset))
步骤2:简化具体Mother类的实现
GivenNameMother和FamilyNameMother只需继承通用基类并指定目标类型,无需重复编写生成逻辑:
from your_module import GivenName, FamilyName class GivenNameMother(VarCharMother[GivenName]): _target_type = GivenName # 可选:覆盖默认字符集以支持UTF-8测试 # _default_charset = string.ascii_uppercase + "àáâãéèêíìîóòôúùûñç" class FamilyNameMother(VarCharMother[FamilyName]): _target_type = FamilyName
核心优势
解决长度同步问题:
所有长度参数直接读取目标类的_MIN_LENGTH和_MAX_LENGTH常量,修改GivenName的长度限制时,GivenNameMother会自动同步,无需手动修改测试代码。消除重复代码:
通用基类封装了所有生成逻辑,新增VarCharType子类时,只需创建简单的Mother子类并指定目标类型即可。灵活扩展字符集:
- 可在具体Mother类中覆盖
_default_charset默认使用UTF-8字符 - 也可在调用时临时传入字符集,例如:
# 用中文生成随机姓氏 chinese_family_name = FamilyNameMother.random_min(charset="赵钱孙李周吴郑王")
- 可在具体Mother类中覆盖
类型安全:
通过泛型T绑定VarCharType子类,所有方法返回的都是具体的GivenName/FamilyName类型,完全不需要使用typing.Any。
额外优化建议(可选)
由于VarCharType继承自不可变类型str,建议将长度验证逻辑移到__new__方法(str子类的最佳实践):
from abc import ABC, abstractmethod class VarCharType(str, ABC): def __new__(cls, value): # 在实例创建前验证长度 cls._validate_length(value) return super().__new__(cls, value) @classmethod def _validate_length(cls, value: str): if not cls._min_length <= len(value) <= cls._max_length: raise TypeError(f'Length must be between {cls._min_length} and {cls._max_length}') @property @classmethod @abstractmethod def _min_length(cls) -> int: pass @property @classmethod @abstractmethod def _max_length(cls) -> int: pass
这样可避免创建不符合长度要求的实例,让VarCharType的实现更符合Python类型规范。
内容的提问来源于stack exchange,提问作者guibos
相关产品推荐
相关产品推荐

