feat(e2e-tests): 添加端到端测试框架及测试用例
refactor(components): 调整头部和页脚布局样式 style(hero-section): 更新徽章动画效果 docs: 添加测试框架README文档 test: 实现首页、导航和联系表单的测试用例 ci: 添加CI测试脚本和配置
This commit is contained in:
@@ -0,0 +1,413 @@
|
||||
"""
|
||||
测试数据生成模块
|
||||
提供测试过程中需要的各种测试数据生成功能
|
||||
"""
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user