测试用例基础:结构、输入输出与断言
说到测试用例,我见过不少新手上来就写代码,结果跑起来全是坑。其实测试用例的结构化设计,比写代码本身更重要。今天我们就聊聊这个基础,但绝对关键的话题。
测试用例的标准结构
一个规范的测试用例,说白了就三块:前置条件、执行步骤、预期结果。我在项目中见过最糟糕的测试,就是只写了「点击按钮,看效果」——这根本不算测试用例。
我个人习惯把测试用例拆成五个字段:
| 字段 | 说明 | 示例 |
|---|---|---|
| 用例ID | 唯一标识,方便追溯 | TC_EDA_001 |
| 测试描述 | 一句话说清测什么 | 验证网表解析模块能正确读取标准Verilog文件 |
| 前置条件 | 测试开始前必须满足的状态 | 已加载标准库文件,输入网表路径合法 |
| 测试步骤 | 按顺序执行的操作 | 1. 调用parseNetlist() 2. 传入test.v文件 |
| 预期结果 | 可验证的最终状态或输出 | 返回对象包含3个module定义,无报错 |
嗯,这里要注意:前置条件经常被忽略。我曾经因为漏写「数据库已初始化」这个条件,导致一个测试跑了三小时全失败,最后发现是环境没准备好。从那以后,我每个用例都强制写前置条件。
输入输出定义:别让模糊毁了你
输入输出定义,是测试用例的「接口契约」。你想想看,如果连输入是什么格式都没说清楚,测试结果怎么可能可靠?
在EDA前端测试中,输入通常分三类:
- 文件输入:Verilog网表、SPEF寄生参数、SDC约束文件
- 参数输入:命令行选项、配置文件中的键值对
- 交互输入:用户点击、键盘事件(GUI测试时)
输出定义更讲究。我建议你明确三点:
- 输出类型:是返回对象、写文件、还是打印日志?
- 输出格式:JSON结构、文本行数、数值精度
- 边界条件:空输入时输出什么?异常时抛出什么异常?
核心原则:输入输出定义必须精确到「能写进代码断言」的程度。比如「返回一个列表」就不够,要写成「返回一个长度为3的列表,每个元素是Module对象,包含name和port_count属性」。
断言机制:测试的「裁判」
断言,就是替你说「这结果对不对」的裁判。没有断言的测试,跑完等于没跑。
我常用的断言分四个层次:
| 断言类型 | 适用场景 | 代码示例 |
|---|---|---|
| 相等性断言 | 验证返回值是否等于预期 | assertEqual(result, expected) |
| 包含性断言 | 验证输出中是否包含特定内容 | assertIn("ERROR", log_text) |
| 类型断言 | 验证返回对象的类型 | assertIsInstance(obj, Netlist) |
| 异常断言 | 验证是否抛出预期异常 | assertRaises(FileNotFoundError) |
举个例子,我在测试网表解析器时,写过这样的断言:
def test_parse_verilog_module():
# 前置条件:准备一个简单的Verilog文件
test_file = "test_module.v"
with open(test_file, "w") as f:
f.write("module adder(a, b, sum); input a, b; output sum; endmodule")
# 执行:调用解析函数
parser = NetlistParser()
result = parser.parse(test_file)
# 断言:验证结果
assert result is not None, "解析结果不应为空"
assert len(result.modules) == 1, "应解析出1个module"
assert result.modules[0].name == "adder", "module名称应为adder"
assert len(result.modules[0].ports) == 3, "应有3个端口"
assert "a" in result.modules[0].ports, "端口a应存在"
我的小技巧:断言信息一定要写清楚。别只写assert x == y,加上描述信息,比如assert x == y, f"期望{y},实际{x}"。这样失败时一眼就能看出问题。
知识体系框架
下面这张图,是我对测试用例基础的理解。它把结构、输入输出、断言串在了一起:
避坑指南:我踩过的三个坑
最后分享几个实战教训:
- 坑一:断言写得太宽松。我曾经只检查返回值不为空,结果返回了一个空列表,测试通过了,但功能根本没实现。现在我会断言具体数值。
- 坑二:输入定义不完整。有一次测试网表解析,我忘了定义「文件编码格式」,结果在Linux上跑通过,Windows上全挂——因为默认编码不同。
- 坑三:忽略异常路径。我习惯只测「正常流程」,直到线上出现非法输入导致崩溃。现在每个用例我都会加一个异常断言。
重要提醒:测试用例不是写给别人看的,是写给未来的自己看的。三个月后你回来看代码,如果看不懂自己写的测试,那说明当时偷懒了。结构清晰、断言明确、输入输出完整——这三条做到了,你的测试用例就是好用例。
好了,测试用例的基础就聊到这儿。记住:结构是骨架,输入输出是血肉,断言是灵魂。三者缺一不可。