如何构建Selenium集中式数据存储以复用测试用例数据
嘿,我来帮你搞定Selenium测试用例间的集中式数据存储与复用问题!作为常年跟自动化测试打交道的人,这事儿我太熟了——集中存储能彻底摆脱每个用例硬编码数据的麻烦,还能让用例间共享动态生成的数据(比如登录token、订单号)。下面是我实战验证过的方案,一步步来:
一、选对集中式数据存储方案
根据你的测试规模和场景,选合适的存储类型:
1. 文件型存储(适合小型项目)
最容易上手的方案,用JSON/YAML/CSV这类结构化文件就行,无需额外服务。
- 搭建步骤:在项目根目录创建一个专门的
test_data文件夹,里面放static_data.json(存固定数据:测试账号、基础配置)和dynamic_data.json(存用例生成的临时数据)。 - 复用示例:
先写个数据管理工具类统一读写:
然后在Selenium用例里调用:import json import os class FileDataManager: def __init__(self, static_path="test_data/static_data.json", dynamic_path="test_data/dynamic_data.json"): self.static_path = static_path self.dynamic_path = dynamic_path # 确保文件存在 self._init_files() def _init_files(self): for path in [self.static_path, self.dynamic_path]: if not os.path.exists(path): with open(path, 'w') as f: json.dump({}, f) def get_static(self, key): with open(self.static_path, 'r') as f: return json.load(f).get(key) def set_dynamic(self, key, value): with open(self.dynamic_path, 'r') as f: dynamic_data = json.load(f) dynamic_data[key] = value with open(self.dynamic_path, 'w') as f: json.dump(dynamic_data, f, indent=2) def get_dynamic(self, key): with open(self.dynamic_path, 'r') as f: return json.load(f).get(key)from selenium import webdriver from data_manager import FileDataManager def test_login_and_save_token(): dm = FileDataManager() driver = webdriver.Chrome() driver.get("https://your-test-site.com/login") # 读取静态测试账号 username = dm.get_static("test_username") password = dm.get_static("test_password") driver.find_element("id", "username").send_keys(username) driver.find_element("id", "password").send_keys(password) driver.find_element("id", "login-btn").click() # 提取登录token并存入动态存储 auth_token = driver.get_cookie("auth_token")["value"] dm.set_dynamic("auth_token", auth_token) driver.quit() def test_use_token_to_create_order(): dm = FileDataManager() driver = webdriver.Chrome() driver.get("https://your-test-site.com/order") # 读取之前存储的token,跳过登录 auth_token = dm.get_dynamic("auth_token") driver.add_cookie({"name": "auth_token", "value": auth_token}) driver.refresh() # 执行下单操作 driver.find_element("id", "create-order").click() order_id = driver.find_element("id", "order-number").text dm.set_dynamic("latest_order_id", order_id) driver.quit()
2. 数据库存储(适合中型项目)
如果测试用例多、并发执行,文件存储可能出现读写冲突,用轻量数据库比如SQLite(无需额外服务)或者MySQL更稳妥。
- 搭建步骤:创建一个
test_data数据库,建两张表:static_data(key, value)和dynamic_data(key, value, expire_time)。 - 复用示例:用Python的
sqlite3模块封装操作类,核心逻辑和文件型类似,只是把读写换成数据库的增删改查。比如:import sqlite3 from datetime import datetime, timedelta class DBDataManager: def __init__(self, db_path="test_data.db"): self.conn = sqlite3.connect(db_path) self._create_tables() def _create_tables(self): cursor = self.conn.cursor() # 静态数据表 cursor.execute(""" CREATE TABLE IF NOT EXISTS static_data ( key TEXT PRIMARY KEY, value TEXT NOT NULL ) """) # 动态数据表(带过期时间,自动清理) cursor.execute(""" CREATE TABLE IF NOT EXISTS dynamic_data ( key TEXT PRIMARY KEY, value TEXT NOT NULL, expire_time DATETIME ) """) self.conn.commit() def get_static(self, key): cursor = self.conn.cursor() cursor.execute("SELECT value FROM static_data WHERE key = ?", (key,)) result = cursor.fetchone() return result[0] if result else None def set_dynamic(self, key, value, expire_hours=24): expire_time = datetime.now() + timedelta(hours=expire_hours) cursor = self.conn.cursor() cursor.execute(""" REPLACE INTO dynamic_data (key, value, expire_time) VALUES (?, ?, ?) """, (key, value, expire_time)) self.conn.commit() def get_dynamic(self, key): cursor = self.conn.cursor() cursor.execute(""" SELECT value FROM dynamic_data WHERE key = ? AND expire_time > ? """, (key, datetime.now())) result = cursor.fetchone() return result[0] if result else None
3. 缓存存储(适合大型/分布式测试)
如果是多机器分布式执行测试,或者需要超快速读写动态数据,用Redis这类缓存服务最合适,还能设置数据过期时间自动清理。
- 搭建步骤:本地或服务器部署Redis,然后用
redis-py库连接。 - 复用示例:
import redis class RedisDataManager: def __init__(self, host="localhost", port=6379, db=0): self.r = redis.Redis(host=host, port=port, db=db, decode_responses=True) def get_static(self, key): return self.r.get(f"static:{key}") def set_static(self, key, value): self.r.set(f"static:{key}", value) def set_dynamic(self, key, value, expire_hours=24): self.r.set(f"dynamic:{key}", value, ex=3600*expire_hours) def get_dynamic(self, key): return self.r.get(f"dynamic:{key}")
二、数据复用的核心逻辑与最佳实践
光有存储还不够,还要注意这些细节,避免踩坑:
- 分层存储:把静态数据(固定账号、配置)和动态数据(临时token、订单号)严格分开,避免混淆和误修改。
- 数据隔离:如果是多测试套件并行,给动态数据加前缀,比如
suite1:auth_token、suite2:auth_token,防止数据互相覆盖。 - 自动清理:测试结束后清理动态数据,比如用测试框架的
teardown方法删除Redis的key,或者清空JSON的dynamic字段,避免影响下一次测试。 - 封装工具类:所有数据操作都通过统一的工具类完成,不要在每个用例里写重复的读写代码,后期维护改一处就行。
- 敏感数据加密:如果存储密码这类敏感信息,要加密后存储,读取时解密,比如用
cryptography库的AES加密。
三、总结
- 小型项目:优先用JSON/YAML,上手快、零成本。
- 中型项目:选SQLite,稳定无冲突,适合多用例执行。
- 大型/分布式项目:用Redis,支持多机器共享,读写速度快。
这些方案我在不同规模的项目里都用过,根据你的实际情况选就行,有问题随时问!
内容的提问来源于stack exchange,提问作者the_code
相关产品推荐
相关产品推荐

