f14002559e
refactor(components): 调整头部和页脚布局样式 style(hero-section): 更新徽章动画效果 docs: 添加测试框架README文档 test: 实现首页、导航和联系表单的测试用例 ci: 添加CI测试脚本和配置
414 lines
14 KiB
Python
414 lines
14 KiB
Python
"""
|
|
测试数据生成模块
|
|
提供测试过程中需要的各种测试数据生成功能
|
|
"""
|
|
|
|
import random
|
|
import string
|
|
import uuid
|
|
import re
|
|
from datetime import datetime, timedelta
|
|
from typing import Any, Dict, List, Optional, Tuple, Union
|
|
from dataclasses import dataclass, field
|
|
from faker import Faker
|
|
|
|
from config.settings import get_settings
|
|
|
|
|
|
class ChineseFaker:
|
|
"""中文测试数据生成器"""
|
|
|
|
def __init__(self, locale: str = "zh_CN"):
|
|
self.faker_zh = Faker("zh_CN")
|
|
self.faker_en = Faker("en_US")
|
|
|
|
def name(self) -> str:
|
|
"""生成中文姓名"""
|
|
return self.faker_zh.name()
|
|
|
|
def first_name(self) -> str:
|
|
"""生成中文名字"""
|
|
return self.faker_zh.first_name()
|
|
|
|
def last_name(self) -> str:
|
|
"""生成中文姓氏"""
|
|
return self.faker_zh.last_name()
|
|
|
|
def phone_number(self) -> str:
|
|
"""生成中国手机号"""
|
|
# 生成以13-19开头的11位手机号
|
|
prefix = random.choice(["13", "14", "15", "16", "17", "18", "19"])
|
|
suffix = "".join(random.choices(string.digits, k=8))
|
|
return prefix + suffix
|
|
|
|
def email(self, domain: Optional[str] = None) -> str:
|
|
"""生成邮箱"""
|
|
if domain:
|
|
return self.faker_zh.email(domain=domain)
|
|
return self.faker_zh.email()
|
|
|
|
def company_name(self) -> str:
|
|
"""生成公司名称"""
|
|
prefixes = ["四川", "成都", "西部", "西南", "中国", "高新"]
|
|
suffixes = ["科技", "信息", "网络", "软件", "数据", "智能", "创新", "未来"]
|
|
name = f"{random.choice(prefixes)}{self.faker_zh.company()}{random.choice(suffixes)}"
|
|
return name
|
|
|
|
def address(self) -> str:
|
|
"""生成中文地址"""
|
|
return self.faker_zh.address().replace("\n", "")
|
|
|
|
def city(self) -> str:
|
|
"""生成城市名"""
|
|
return self.faker_zh.city()
|
|
|
|
def province(self) -> str:
|
|
"""生成省份名"""
|
|
return self.faker_zh.province()
|
|
|
|
def job_title(self) -> str:
|
|
"""生成职位名称"""
|
|
titles = [
|
|
"软件工程师", "产品经理", "UI设计师", "测试工程师",
|
|
"项目主管", "技术总监", "架构师", "数据分析师",
|
|
"运维工程师", "产品运营", "市场经理", "销售代表"
|
|
]
|
|
return random.choice(titles)
|
|
|
|
def username(self) -> str:
|
|
"""生成用户名"""
|
|
return self.faker_zh.user_name()
|
|
|
|
def password(self, length: int = 12) -> str:
|
|
"""生成密码"""
|
|
chars = string.ascii_letters + string.digits + "!@#$%^&*"
|
|
return "".join(random.choices(chars, k=length))
|
|
|
|
def text(self, max_chars: int = 200) -> str:
|
|
"""生成随机中文文本"""
|
|
paragraphs = []
|
|
for _ in range(random.randint(1, 3)):
|
|
sentences = []
|
|
for _ in range(random.randint(3, 8)):
|
|
sentence_len = random.randint(10, 30)
|
|
sentence = self.faker_zh.sentence(nb_words=sentence_len)
|
|
sentences.append(sentence)
|
|
paragraphs.append("。".join(sentences) + "。")
|
|
return "".join(paragraphs)[:max_chars]
|
|
|
|
def sentence(self, nb_words: int = 20) -> str:
|
|
"""生成随机句子"""
|
|
return self.faker_zh.sentence(nb_words=nb_words)
|
|
|
|
def word(self) -> str:
|
|
"""生成随机词语"""
|
|
return self.faker_zh.word()
|
|
|
|
def words(self, nb: int = 5) -> List[str]:
|
|
"""生成随机词语列表"""
|
|
return self.faker_zh.words(nb=nb)
|
|
|
|
def date_of_birth(self, start_year: int = 1960, end_year: int = 2000) -> str:
|
|
"""生成出生日期"""
|
|
return self.faker_zh.date_of_birth(
|
|
minimum_age=end_year - datetime.now().year,
|
|
maximum_age=start_year - datetime.now().year
|
|
).strftime("%Y-%m-%d")
|
|
|
|
def credit_card_number(self) -> str:
|
|
"""生成信用卡号(测试用)"""
|
|
return self.faker_zh.credit_card_number()
|
|
|
|
def credit_card_provider(self) -> str:
|
|
"""生成信用卡提供商"""
|
|
providers = ["Visa", "MasterCard", "银联", "JCB", "American Express"]
|
|
return random.choice(providers)
|
|
|
|
def ipv4(self) -> str:
|
|
"""生成IPv4地址"""
|
|
return self.faker_zh.ipv4()
|
|
|
|
def mac_address(self) -> str:
|
|
"""生成MAC地址"""
|
|
return self.faker_zh.mac_address()
|
|
|
|
def url(self) -> str:
|
|
"""生成URL"""
|
|
return self.faker_zh.url()
|
|
|
|
def uri_path(self) -> str:
|
|
"""生成URI路径"""
|
|
return self.faker_zh.uri_path()
|
|
|
|
def user_agent(self) -> str:
|
|
"""生成User-Agent"""
|
|
return self.faker_zh.user_agent()
|
|
|
|
def hex_color(self) -> str:
|
|
"""生成十六进制颜色"""
|
|
return self.faker_zh.hex_color()
|
|
|
|
def rgb_color(self) -> Tuple[int, int, int]:
|
|
"""生成RGB颜色"""
|
|
return self.faker_zh.rgb_color()
|
|
|
|
|
|
class EnglishFaker:
|
|
"""英文测试数据生成器"""
|
|
|
|
def __init__(self):
|
|
self.faker = Faker("en_US")
|
|
|
|
def name(self) -> str:
|
|
"""生成英文姓名"""
|
|
return self.faker.name()
|
|
|
|
def first_name(self) -> str:
|
|
"""生成英文名字"""
|
|
return self.faker.first_name()
|
|
|
|
def last_name(self) -> str:
|
|
"""生成英文姓氏"""
|
|
return self.faker.last_name()
|
|
|
|
def email(self, domain: Optional[str] = None) -> str:
|
|
"""生成邮箱"""
|
|
if domain:
|
|
return self.faker.email(domain=domain)
|
|
return self.faker.email()
|
|
|
|
def phone_number(self) -> str:
|
|
"""生成美国电话号码"""
|
|
return self.faker.phone_number()
|
|
|
|
def company(self) -> str:
|
|
"""生成公司名称"""
|
|
return self.faker.company()
|
|
|
|
def address(self) -> str:
|
|
"""生成地址"""
|
|
return self.faker.address().replace("\n", ", ")
|
|
|
|
def city(self) -> str:
|
|
"""生成城市名"""
|
|
return self.faker.city()
|
|
|
|
def state(self) -> str:
|
|
"""生成州/省名"""
|
|
return self.faker.state()
|
|
|
|
def country(self) -> str:
|
|
"""生成国家名"""
|
|
return self.faker.country()
|
|
|
|
def zip_code(self) -> str:
|
|
"""生成邮编"""
|
|
return self.faker.zipcode()
|
|
|
|
def username(self) -> str:
|
|
"""生成用户名"""
|
|
return self.faker.user_name()
|
|
|
|
def password(self, length: int = 12) -> str:
|
|
"""生成密码"""
|
|
chars = string.ascii_letters + string.digits + "!@#$%^&*"
|
|
return "".join(random.choices(chars, k=length))
|
|
|
|
def text(self, max_chars: int = 200) -> str:
|
|
"""生成随机英文文本"""
|
|
return self.faker.text(max_nb_chars=max_chars)
|
|
|
|
def sentence(self, nb_words: int = 10) -> str:
|
|
"""生成随机句子"""
|
|
return self.faker.sentence(nb_words=nb_words)
|
|
|
|
def paragraph(self, nb_sentences: int = 3) -> str:
|
|
"""生成段落"""
|
|
return self.faker.paragraph(nb_sentences=nb_sentences)
|
|
|
|
def date_of_birth(self, start_year: int = 1960, end_year: int = 2000) -> str:
|
|
"""生成出生日期"""
|
|
return self.faker.date_of_birth(
|
|
minimum_age=end_year - datetime.now().year,
|
|
maximum_age=start_year - datetime.now().year
|
|
).strftime("%Y-%m-%d")
|
|
|
|
def date_between(self, start_date: str, end_date: str) -> str:
|
|
"""生成日期范围"""
|
|
start = datetime.strptime(start_date, "%Y-%m-%d")
|
|
end = datetime.strptime(end_date, "%Y-%m-%d")
|
|
return self.faker.date_between(start, end).strftime("%Y-%m-%d")
|
|
|
|
|
|
class TestDataGenerator:
|
|
"""测试数据生成器主类"""
|
|
|
|
def __init__(self):
|
|
self.settings = get_settings()
|
|
self.zh_faker = ChineseFaker()
|
|
self.en_faker = EnglishFaker()
|
|
|
|
def generate_contact_form_data(
|
|
self,
|
|
use_valid: bool = True,
|
|
lang: str = "zh"
|
|
) -> Dict[str, str]:
|
|
"""生成联系表单数据"""
|
|
if use_valid:
|
|
if lang == "zh":
|
|
return {
|
|
"name": self.zh_faker.name(),
|
|
"phone": self.zh_faker.phone_number(),
|
|
"email": self.zh_faker.email(domain="example.com"),
|
|
"subject": self.zh_faker.sentence(nb_words=8),
|
|
"message": self.zh_faker.text(max_chars=300)
|
|
}
|
|
else:
|
|
return {
|
|
"name": self.en_faker.name(),
|
|
"phone": self.en_faker.phone_number(),
|
|
"email": self.en_faker.email(domain="example.com"),
|
|
"subject": self.en_faker.sentence(nb_words=8),
|
|
"message": self.en_faker.paragraph(nb_sentences=3)
|
|
}
|
|
else:
|
|
return self.settings.test_form_data.get("invalid", {
|
|
"email": "invalid-email",
|
|
"phone": "123"
|
|
})
|
|
|
|
def generate_user_profile(self, lang: str = "zh") -> Dict[str, Any]:
|
|
"""生成用户资料数据"""
|
|
if lang == "zh":
|
|
return {
|
|
"name": self.zh_faker.name(),
|
|
"email": self.zh_faker.email(domain="example.com"),
|
|
"phone": self.zh_faker.phone_number(),
|
|
"address": self.zh_faker.address(),
|
|
"job_title": self.zh_faker.job_title(),
|
|
"company": self.zh_faker.company_name(),
|
|
"date_of_birth": self.zh_faker.date_of_birth()
|
|
}
|
|
else:
|
|
return {
|
|
"name": self.en_faker.name(),
|
|
"email": self.en_faker.email(domain="example.com"),
|
|
"phone": self.en_faker.phone_number(),
|
|
"address": self.en_faker.address(),
|
|
"job_title": random.choice([
|
|
"Software Engineer", "Product Manager", "Designer",
|
|
"Marketing Manager", "Sales Representative", "Data Analyst"
|
|
]),
|
|
"company": self.en_faker.company(),
|
|
"date_of_birth": self.en_faker.date_of_birth()
|
|
}
|
|
|
|
def generate_search_query(self) -> str:
|
|
"""生成搜索查询"""
|
|
topics = [
|
|
"软件开发", "云计算", "人工智能", "数据分析",
|
|
"数字化转型", "企业服务", "智能制造", "物联网"
|
|
]
|
|
return random.choice(topics)
|
|
|
|
def generate_news_article(self) -> Dict[str, Any]:
|
|
"""生成新闻文章数据"""
|
|
return {
|
|
"title": self.zh_faker.sentence(nb_words=12),
|
|
"summary": self.zh_faker.text(max_chars=200),
|
|
"content": self.zh_faker.text(max_chars=1000),
|
|
"author": self.zh_faker.name(),
|
|
"publish_date": datetime.now().strftime("%Y-%m-%d"),
|
|
"category": random.choice(["公司新闻", "行业动态", "产品发布", "技术文章"])
|
|
}
|
|
|
|
def generate_product_data(self) -> Dict[str, Any]:
|
|
"""生成产品数据"""
|
|
products = [
|
|
{"name": "睿新ERP管理系统", "category": "企业软件"},
|
|
{"name": "睿新客户关系管理系统", "category": "企业软件"},
|
|
{"name": "睿新协同办公平台", "category": "企业软件"},
|
|
{"name": "睿新商业智能平台", "category": "数据产品"},
|
|
{"name": "睿新物联网平台", "category": "物联网"},
|
|
{"name": "睿新AI智能应用套件", "category": "人工智能"}
|
|
]
|
|
product = random.choice(products)
|
|
return {
|
|
"name": product["name"],
|
|
"category": product["category"],
|
|
"description": self.zh_faker.text(max_chars=300),
|
|
"features": random.sample([
|
|
"高性能", "高可用", "易扩展", "安全可靠",
|
|
"智能化", "云原生", "移动优先", "低代码"
|
|
], k=4),
|
|
"price": round(random.uniform(1000, 100000), 2)
|
|
}
|
|
|
|
def generate_company_info(self) -> Dict[str, str]:
|
|
"""生成公司信息"""
|
|
return {
|
|
"name": self.zh_faker.company_name(),
|
|
"short_name": "".join(self.zh_faker.company_name()[:4]),
|
|
"slogan": self.zh_faker.sentence(nb_words=6),
|
|
"description": self.zh_faker.text(max_chars=200),
|
|
"address": self.zh_faker.address(),
|
|
"phone": self.zh_faker.phone_number(),
|
|
"email": self.zh_faker.email(domain="example.com"),
|
|
"website": self.zh_faker.url()
|
|
}
|
|
|
|
def generate_dates(self, count: int = 10) -> List[str]:
|
|
"""生成日期列表"""
|
|
dates = []
|
|
base_date = datetime.now()
|
|
for i in range(count):
|
|
date = base_date - timedelta(days=random.randint(0, 365))
|
|
dates.append(date.strftime("%Y-%m-%d"))
|
|
return dates
|
|
|
|
def generate_unique_id(self) -> str:
|
|
"""生成唯一ID"""
|
|
return str(uuid.uuid4())
|
|
|
|
def generate_order_number(self) -> str:
|
|
"""生成订单号"""
|
|
prefix = "ORD"
|
|
timestamp = datetime.now().strftime("%Y%m%d%H%M%S")
|
|
random_suffix = "".join(random.choices(string.ascii_uppercase + string.digits, k=6))
|
|
return f"{prefix}{timestamp}{random_suffix}"
|
|
|
|
def generate_numeric_range(
|
|
self,
|
|
min_val: int = 1,
|
|
max_val: int = 100,
|
|
decimals: int = 0
|
|
) -> Union[int, float]:
|
|
"""生成数值范围"""
|
|
value = random.uniform(min_val, max_val)
|
|
return round(value, decimals) if decimals else int(value)
|
|
|
|
def generate_boolean(self) -> bool:
|
|
"""生成布尔值"""
|
|
return random.choice([True, False])
|
|
|
|
def generate_choice(self, options: List[Any]) -> Any:
|
|
"""从列表中随机选择一个"""
|
|
return random.choice(options)
|
|
|
|
def generate_color(self, format: str = "hex") -> Union[str, Tuple[int, int, int]]:
|
|
"""生成颜色值"""
|
|
if format == "hex":
|
|
return self.zh_faker.hex_color()
|
|
elif format == "rgb":
|
|
return self.zh_faker.rgb_color()
|
|
return self.zh_faker.hex_color()
|
|
|
|
|
|
# 全局测试数据生成器实例
|
|
test_data_generator = TestDataGenerator()
|
|
|
|
|
|
def get_test_data_generator() -> TestDataGenerator:
|
|
"""获取测试数据生成器"""
|
|
return test_data_generator
|