第二章:项目结构搭建——从零开始搭架子
说实话,很多初学者拿到一个自动化测试项目,第一反应就是「先写代码」。我当年也是这样,结果呢?项目写到一半,配置文件散落一地,日志不知道存哪去了,想找个测试数据得翻半天文件夹。嗯,这种痛,经历过的人都懂。
今天我们就来聊聊,怎么把项目的「骨架」搭好。说白了,就是三个事:目录结构怎么分、配置怎么管、日志怎么记。这三样搞定了,后面写代码会顺畅很多。
2.1 项目目录结构——别小看这个事
我见过不少团队,项目目录长得跟迷宫似的。你想想看,一个新同事入职,光找测试用例就得花半小时。这效率,能高吗?
我个人习惯用这种分层结构,清晰又好维护:
auto_test_framework/
├── config/ # 配置文件目录
│ ├── config.ini
│ └── logging.yaml
├── logs/ # 日志输出目录
├── test_cases/ # 测试用例
│ ├── test_login.py
│ └── test_order.py
├── common/ # 公共模块
│ ├── logger.py # 日志封装
│ └── config_reader.py # 配置读取
├── data/ # 测试数据
│ └── test_data.xlsx
├── reports/ # 测试报告
├── requirements.txt # 依赖清单
└── run.py # 主入口
核心原则:每个目录只干一件事。配置归配置,日志归日志,用例归用例。别混在一起,否则后期维护会想哭。
我在项目中遇到过最坑的事:有人把数据库连接密码直接写在测试代码里。结果代码一提交,密码全泄露了。从那以后,我强制要求所有敏感信息必须走配置文件,而且配置文件要加入 .gitignore。
⚠️ 注意:千万不要把 config 目录下的配置文件提交到 Git 仓库!建议只提交一个 config.ini.example 模板文件,让每个开发者自己复制修改。
2.2 配置管理——用 config.ini 还是 yaml?
这个问题经常有人问。我的答案是:看场景。
config.ini 适合简单的键值对配置,比如数据库地址、端口号这些。yaml 呢?它支持层级结构,适合复杂的配置场景,比如多环境切换、测试数据分组。
先看 config.ini 的写法:
[database]
host = 127.0.0.1
port = 3306
user = root
password = 123456
[test]
browser = chrome
timeout = 30
读取它的代码也很简单:
import configparser
config = configparser.ConfigParser()
config.read('config/config.ini', encoding='utf-8')
db_host = config.get('database', 'host')
browser = config.get('test', 'browser')
再看 yaml 的写法,我个人更喜欢这种:
database:
host: 127.0.0.1
port: 3306
user: root
password: 123456
test:
browser: chrome
timeout: 30
environments:
- dev
- staging
- prod
读取 yaml 需要安装 PyYAML 库:
import yaml
with open('config/config.yaml', 'r', encoding='utf-8') as f:
config = yaml.safe_load(f)
db_host = config['database']['host']
env_list = config['test']['environments']
💡 我的建议:如果项目规模不大(比如就两三个环境),用 config.ini 就够了。如果项目要支持多环境、多套配置,果断上 yaml。我曾经在一个大项目里用 config.ini 写了 200 多行,后来重构时全改成 yaml 了,清爽多了。
2.3 日志系统——别让调试变成噩梦
日志这东西,平时觉得无所谓,一出问题就抓瞎。我记得有一次线上环境出了 bug,测试同学说「我跑了呀,没报错啊」。结果一看日志,全是 print 出来的,根本没法定位问题。
Python 自带的 logging 模块其实很强大,关键是要用好它。我一般会封装一个日志工具类:
import logging
import os
from logging.handlers import RotatingFileHandler
class Logger:
def __init__(self, name='auto_test', log_dir='logs'):
self.logger = logging.getLogger(name)
self.logger.setLevel(logging.DEBUG)
# 确保日志目录存在
if not os.path.exists(log_dir):
os.makedirs(log_dir)
# 文件处理器:按大小轮转,每个文件10MB,保留5个
file_handler = RotatingFileHandler(
filename=f'{log_dir}/{name}.log',
maxBytes=10*1024*1024,
backupCount=5,
encoding='utf-8'
)
file_handler.setLevel(logging.INFO)
# 控制台处理器
console_handler = logging.StreamHandler()
console_handler.setLevel(logging.DEBUG)
# 定义格式
formatter = logging.Formatter(
'%(asctime)s - %(name)s - %(levelname)s - %(filename)s:%(lineno)d - %(message)s'
)
file_handler.setFormatter(formatter)
console_handler.setFormatter(formatter)
# 避免重复添加处理器
if not self.logger.handlers:
self.logger.addHandler(file_handler)
self.logger.addHandler(console_handler)
def get_logger(self):
return self.logger
使用起来也很简单:
from common.logger import Logger
log = Logger('test_login').get_logger()
log.info('开始执行登录测试')
log.debug('当前浏览器: Chrome')
log.error('登录失败,用户名或密码错误')
关键点:日志级别要设置合理。开发调试时用 DEBUG,日常运行用 INFO,只有真正出问题才用 ERROR。别把所有信息都打成 INFO,否则日志文件会膨胀得很快。
我曾经犯过一个错:在生产环境把日志级别设成了 DEBUG,结果一天下来日志文件涨到了 2GB。磁盘直接爆了,整个服务挂了半天。嗯,从那以后我学乖了,生产环境一律 INFO 起步。
2.4 配置与日志的联动
你想想看,如果每次改日志级别都要改代码,那多麻烦。更好的做法是:把日志配置也放到配置文件里。
比如在 config.ini 里加一段:
[logging]
level = INFO
log_dir = logs
max_bytes = 10485760
backup_count = 5
然后在初始化日志时读取这些配置:
import configparser
config = configparser.ConfigParser()
config.read('config/config.ini')
log_level = config.get('logging', 'level')
log_dir = config.get('logging', 'log_dir')
# 根据配置初始化日志
log = Logger('auto_test', log_dir=log_dir)
log.get_logger().setLevel(getattr(logging, log_level))
💡 小技巧:我习惯在项目启动时先加载配置,再初始化日志。这样如果配置加载失败,日志还能记录错误信息。顺序很重要,别搞反了。
2.5 避坑指南——我踩过的那些坑
- 路径问题:千万别用相对路径写死。我建议用 os.path.dirname(__file__) 动态获取当前文件路径,再拼接其他目录。这样不管项目放在哪,都能正常工作。
- 编码问题:配置文件一定要指定 encoding='utf-8',否则中文注释会乱码。我见过有人因为这个排查了半天。
- 日志重复:每次调用 Logger 类时,如果重复添加处理器,日志会重复输出。记得加个判断:if not self.logger.handlers。
- 敏感信息:密码、密钥这些别硬编码。用环境变量或者加密的配置文件。我曾经在演示时不小心把数据库密码打印到日志里,场面一度很尴尬。
好了,项目结构这块就聊到这。下一章我们开始写真正的测试用例,到时候这些配置和日志就能派上用场了。记住一句话:架子搭得好,后面少烦恼。
总结一下本章要点:
- 目录结构要分层清晰,各司其职
- 配置管理推荐 yaml,简单场景用 config.ini
- 日志系统用 logging 模块,封装成工具类复用
- 配置和日志要联动,避免硬编码
- 注意路径、编码、重复处理器等细节
公众号:蓝海资料掘金营,微信deep3321