本文目录导读:

构建Python测试数据工厂(Test Data Factory)的核心思想是将测试数据的创建逻辑封装起来,提供灵活、可复用的数据生成方式,以下是几种常用的构建方法:
基础数据工厂模式
1 简单的函数工厂
def create_user(name="测试用户", age=25, email=None):
if email is None:
email = f"{name.lower()}@example.com"
return {
"name": name,
"age": age,
"email": email,
"is_active": True,
"created_at": "2024-01-01"
}
# 使用默认值
user1 = create_user()
# 覆盖特定字段
user2 = create_user(name="张三", age=30)
2 类工厂模式
class UserFactory:
@staticmethod
def create(name="测试用户", age=25, **kwargs):
user = {
"name": name,
"age": age,
"email": f"{name.lower()}@example.com",
"is_active": True,
"created_at": "2024-01-01"
}
user.update(kwargs) # 允许额外字段
return user
@staticmethod
def create_batch(count=5, **kwargs):
return [UserFactory.create(**kwargs) for _ in range(count)]
# 使用
user = UserFactory.create()
users = UserFactory.create_batch(count=3, age=20)
使用Faker库生成真实数据
from faker import Faker
from datetime import datetime, timedelta
import random
fake = Faker('zh_CN') # 中文数据
class UserFactory:
@staticmethod
def create(name=None, **kwargs):
user = {
"name": name or fake.name(),
"age": random.randint(18, 65),
"email": fake.email(),
"phone": fake.phone_number(),
"address": fake.address(),
"is_active": random.choice([True, False]),
"salary": round(random.uniform(5000, 50000), 2),
"join_date": fake.date_between(start_date='-2y', end_date='today')
}
user.update(kwargs)
return user
数据工厂参数化
1 支持条件生成
class OrderFactory:
@staticmethod
def create(
status="pending",
amount=None,
items=None,
discount=0
):
if amount is None:
amount = random.randint(100, 1000)
if items is None:
items = random.randint(1, 10)
if discount > 0:
amount = int(amount * (1 - discount))
# 根据状态设置不同的数据
if status == "cancelled":
is_active = False
cancel_reason = "客户取消"
else:
is_active = True
cancel_reason = None
return {
"order_id": fake.uuid4(),
"status": status,
"amount": amount,
"items_count": items,
"discount": discount,
"is_active": is_active,
"cancel_reason": cancel_reason,
"created_at": datetime.now()
}
2 构建器模式(Builder Pattern)
class UserBuilder:
def __init__(self):
self.data = {
"name": "默认用户",
"age": 25,
"email": "default@example.com",
"role": "user"
}
def with_name(self, name):
self.data["name"] = name
return self
def with_age(self, age):
self.data["age"] = age
return self
def as_admin(self):
self.data["role"] = "admin"
return self
def build(self):
return self.data.copy()
# 使用
user = UserBuilder()\
.with_name("管理员")\
.with_age(30)\
.as_admin()\
.build()
关联数据工厂
class OrderFactory:
@staticmethod
def create_with_items(user_data=None, item_count=3):
if user_data is None:
user_data = UserFactory.create()
items = []
for i in range(item_count):
items.append({
"product_id": fake.uuid4(),
"name": fake.word(),
"price": random.randint(10, 100),
"quantity": random.randint(1, 5),
"user_id": user_data["id"] if "id" in user_data else None
})
total = sum(item["price"] * item["quantity"] for item in items)
return {
"order_id": fake.uuid4(),
"user": user_data,
"items": items,
"total": total,
"created_at": datetime.now()
}
测试专用数据工厂
class TestUserFactory:
"""专门为测试用例设计的数据工厂"""
# 预定义测试场景
SCENARIOS = {
"valid_user": {
"username": "testuser",
"password": "ValidPass123!",
"email": "test@example.com"
},
"invalid_email": {
"username": "testuser",
"password": "ValidPass123!",
"email": "invalid-email"
},
"short_password": {
"username": "testuser",
"password": "123",
"email": "test@example.com"
}
}
@classmethod
def create_from_scenario(cls, scenario_name, **overrides):
if scenario_name not in cls.SCENARIOS:
raise ValueError(f"Unknown scenario: {scenario_name}")
data = cls.SCENARIOS[scenario_name].copy()
data.update(overrides)
return data
@classmethod
def create_null_values(cls):
"""创建包含空值的测试数据"""
return {
"username": None,
"password": "",
"email": None
}
高级:使用Pydantic验证
from pydantic import BaseModel, validator
from typing import Optional
import random
class UserData(BaseModel):
name: str
age: int
email: Optional[str] = None
salary: float
@validator('age')
def validate_age(cls, v):
if v < 0 or v > 150:
raise ValueError('Invalid age')
return v
class UserFactory:
@staticmethod
def create_valid(**kwargs) -> UserData:
"""创建有效数据"""
data = {
"name": "测试用户",
"age": 25,
"email": "test@example.com",
"salary": 10000.0
}
data.update(kwargs)
return UserData(**data)
@staticmethod
def create_random() -> UserData:
"""创建随机有效数据"""
return UserData(
name=fake.name(),
age=random.randint(18, 65),
email=fake.email(),
salary=round(random.uniform(5000, 50000), 2)
)
最佳实践
1 工厂配置管理
import os
from dotenv import load_dotenv
load_dotenv()
class DataFactory:
"""可配置的数据工厂"""
@staticmethod
def get_config():
return {
"default_locale": os.getenv("TEST_LOCALE", "zh_CN"),
"batch_size": int(os.getenv("TEST_BATCH_SIZE", "10")),
"use_random": os.getenv("TEST_USE_RANDOM", "true").lower() == "true"
}
@classmethod
def create_user(cls, **kwargs):
config = cls.get_config()
if config["use_random"] and not kwargs:
return UserFactory.create_random()
return UserFactory.create(**kwargs)
2 工厂组合使用
class TestDataComposer:
"""组合多个工厂生成完整测试场景"""
@staticmethod
def create_complete_order_scenario():
user = UserFactory.create()
products = ProductFactory.create_batch(3)
order = OrderFactory.create_with_items(
user_data=user,
items_data=products
)
return {
"user": user,
"products": products,
"order": order
}
构建测试数据工厂的关键点:
- 封装性:将数据创建逻辑统一管理
- 灵活性:支持参数覆盖和默认值
- 可复用性:一次定义,多处使用
- 可读性:清晰的接口和文档
- 可维护性:集中管理测试数据变更
根据项目复杂度选择合适的方法,简单的项目使用基础工厂即可,复杂项目考虑使用Builder模式或结合Pydantic进行数据验证。
版权声明:足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
足球直播
足球直播
足球直播
足球直播
足球直播
中超直播
中超直播
中超直播
中超直播
中超直播
英超直播
英超直播
英超直播
英超直播
英超直播
德甲直播
德甲直播
德甲直播
德甲直播
德甲直播
西甲直播
西甲直播
西甲直播
西甲直播
西甲直播
意甲直播
意甲直播
意甲直播
意甲直播
意甲直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播