1个脚本跑1000组数据!美团测试总监亲授数据驱动实战

一、残酷对比:普通VS数据驱动脚本的维护成本

# ❌ 传统硬编码脚本(需求变更必崩溃)   
def test_login():      
 driver.find_element(By.ID, "username").send_keys("admin")       driver.find_element(By.ID, "password").send_keys("123456")   # ✅ 数据驱动脚本(参数化应对变化)   import csv   @pytest.mark.parametrize("user,pwd", read_csv("login_data.csv"))   def test_login(user, pwd):       driver.find_element(By.ID, "username").send_keys(user)       driver.find_element(By.ID, "password").send_keys(pwd)

💡 企业收益:
  • 新增测试数据 → 无需修改代码

  • 测试逻辑变更 → 只改1处函数

  • 失败用例定位 → 精准到数据行

二、四步落地数据驱动框架(含避坑指南)

步骤1:数据源选型决策树

 

避坑: CSV文件禁止用ExC++el编辑!(编码问题导致读取失败)

步骤2:数据加载器封装(附完整代码)

# 支持多源数据的工厂模式实现   def load_data(source):      
 if source.endswith(".csv"):          
  with open(source, encoding="utf-8-sig") as f:  
  # 解决BOM头问题               
  return list(csv.DictReader(f))       
  elif source.endswith(".json"):           
  return json.load(open(source))       
  elif source.startswith("MySQL:"):           
  return query_db(source.split(":")[1])  
  # 企业级数据库连接器   
  # 获取今日头条的测试数据   
  test_data = load_data("testcases/search_toutiao.json")

步骤3:Pytest高级参数化技巧

场景: 多账号权限验证(每个账号测不同功能)

# ✅ 动态生成测试ID(报告更直观)   
@pytest.mark.parametrize("user", test_data, ids=lambda d: f"{d['role']}权限测试")   
def test_permission(user):      
 login(user["name"], user["pwd"])       
 assert check_access(user["expected_features"])   
 # 报告显示:  
  # ✓ 管理员权限测试

配置pytest.ini:

[pytest]   addopts = --tb=short --durations=0   ; 失败时重跑2次   reruns = 2   ; 自动保存失败用例数据   failed_data_file = reports/failed_cases.json

定位失败数据:

// failed_cases.json   
{     
"test_permission[运营人员权限测试]": 
{      
 "user": {"name": "ops01", "pwd": "*****", "role": "operator"},       
 "error": "AssertionError: 缺少'删除'权限"    
  }  
  }

三、企业级数据安全方案(金融项目实战)

场景:测试含敏感数据(银行卡/身份证)

传统风险:

  • 测试脚本含明文密码

  • CSV文件泄露客户信息

解决方案:

from cryptography.fernet import Fernet   
# ✅ 数据加密存储   
key = Fernet.generate_key()  
 cipher = Fernet(key)   
 encrypted_pwd = cipher.encrypt(b"123456")  
 # 写入测试数据文件  
 # ✅ 运行时动态解密  
  @pytest.fixture(scope="function")   
  def decrypt_data(request):      
   request.param["password"] = cipher.decrypt(request.param["enc_password"]).decode()       
   return request.param   
   # 使用:   
   @pytest.mark.parametrize("user", test_data, indirect=True)  
    def test_payment(user):       
    pay(user["card_num"], user["password"])