news 2026/6/25 21:18:34

调试与测试:Bug查得快,写得稳

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
调试与测试:Bug查得快,写得稳

一、问题背景:一个空字符串坑了我3天

去年有件让我印象特别深刻的事。

写了一个MES数据导入脚本,跑了半年没问题。突然有一天,某批次的厚度平均值算出来是负数。

查了3天,最后发现:**有一行的厚度值被MES导成了空字符串,被我转成了0。**

更坑的是,上个月也有一批数据少一个值,但因为数据量大,一个0对平均值影响小,没发现。这次恰好样本少,一个0直接拉偏了整个平均值。

**为什么没发现?** 因为写代码的时候只想了"正常情况",没想"数据不完美"的情况。

**教训**:代码能跑 ≠ 代码没问题。Bug藏得越深,排查越痛苦。

**学完这一篇,你能做到:**

1. 用 `print` + `breakpoint` 快速找Bug

2. 用 `assert` 在代码里自动检查数据

3. 用 `unittest` 写简单的测试,上线前就发现问题

────────────────────────────────────────

二、技术原理:调试三板斧

2.1 第一斧:print调试

最简单但也最有效:

def calc_avg(data):

print(f"[调试] 输入数据: {data}") # 看输入

result = sum(data) / len(data)

print(f"[调试] 计算结果: {result}") # 看输出

return result

哪步不对,一看print就知道。缺点是调试完要删掉这些print,不能忘。

2.2 第二斧:assert断言

更高级的"自检"——条件不满足就直接报错:

def calc_avg(data):

assert len(data) > 0, "数据不能为空!"

assert all(isinstance(x, (int, float)) for x in data), "数据里混了非数字!"

return sum(data) / len(data)

# 正常调用——没问题

calc_avg([1250, 1248, 1251])

# 传空列表——assert弹出来

calc_avg([]) # AssertionError: 数据不能为空!

**为什么值得学?** `assert` 像代码里的"安检门"——数据进来先检查一遍,不对立刻停。这样不会出现"算了一个错的结果还在继续用"的情况。

2.3 第三斧:breakpoint断点

def complex_calculation(data):

total = 0

breakpoint() # 程序跑到这里会暂停,进入交互式模式

for x in data:

total += x

return total

complex_calculation([1, 2, 3])

# 当你看到 >>> 提示符时,可以输入变量名看值:

# >>> data -> [1, 2, 3]

# >>> total -> 0

# >>> quit() -> 退出继续跑

**实用技巧**:在 `>>>` 后输入变量名就能看值,输入 `quit()` 或按 `Ctrl+Z` 继续运行。

────────────────────────────────────────

三、实战案例:给你的代码写测试

3.1 先写一个简单函数

def process_lot(data, lot_id="Unknown"):

"""

处理一批Lot数据

返回: 均值和是否合格

"""

# 自检(assert)

assert len(data) > 0, f"Lot {lot_id} 数据为空"

assert all(isinstance(x, (int, float)) for x in data), "数据必须为数字"

avg = sum(data) / len(data)

std = (sum((x - avg)**2 for x in data) / (len(data) - 1)) ** 0.5

passed = std < 3.0 # 标准差<3算合格

return {"lot_id": lot_id, "avg": round(avg, 2), "std": round(std, 2), "pass": passed}

3.2 写测试文件

新建 `test_process_lot.py`:

import unittest

from process_lot import process_lot # 假设函数在上面的文件里

class TestProcessLot(unittest.TestCase):

"""测试 process_lot 函数"""

def test_normal_lot(self):

"""正常数据"""

result = process_lot([1250.5, 1248.3, 1251.2], "FAB-001")

self.assertEqual(result['lot_id'], "FAB-001")

self.assertTrue(result['pass']) # 应该合格

def test_bad_lot(self):

"""标准差大的数据"""

result = process_lot([1250, 1240, 1260], "FAB-002")

self.assertFalse(result['pass']) # 应该不合格

def test_single_value(self):

"""边界情况:只有一个值"""

result = process_lot([1250], "FAB-003")

self.assertEqual(result['std'], 0) # 标准差为0

self.assertTrue(result['pass']) # 标准差=0算合格

if __name__ == '__main__':

unittest.main()

3.3 运行测试

python test_process_lot.py

输出:

...

----------------------------------------------------------------------

Ran 3 tests in 0.001s

OK # 全部通过!

**把test跑失败**:在 `process_lot` 里改点什么(比如把 `avg = sum(data) / len(data)` 改成 `avg = sum(data) / 2`),再跑测试看看——你会看到 `FAILED (failures=1)`。

一个好的函数应该有对应的测试。每次改代码,跑一遍测试就知道有没有改坏别的。

────────────────────────────────────────

四、效果对比

| 代码 | 之前 | 之后 |

|------|------|------|

| 排查Bug | 3天 | 5分钟 |

| 上线信心 | "但愿没问题" | "测试全过" |

| 改代码 | 改完忐忑 | 改完跑测试 |

────────────────────────────────────────

五、自己动手

# 练习:给你自己的函数写测试

# 第1步:写一个函数

def calc_cpk(data, usl=1253, lsl=1247):

"""计算Cpk"""

avg = sum(data) / len(data)

std = (sum((x - avg)**2 for x in data) / (len(data) - 1)) ** 0.5

return min((usl - avg) / (3 * std), (avg - lsl) / (3 * std))

# 第2步:写测试

# 测试用例1:正常数据,Cpk应该 > 1.0

# 测试用例2:数据波动很大,Cpk应该 < 1.0

# 测试用例3:传空列表,应该怎么办?

# ✏️ 下面写你的代码

**思考题**:

1. 测试文件 `test_xxx.py` 为什么以 `test` 开头?试试改成别的名字

2. 如果函数里用了 `print` 而不是 `return`,能测试吗?

3. 你猜 `self.assertEqual` 和 `assert a == b` 有什么区别?

────────────────────────────────────────

六、常见误区

| 问题 | 表现 | 解决 |

|------|------|------|

| 没写测试就上线 | 线上出Bug才慌 | 写一行测试不费时间 |

| 只有正常情况测试 | 边界条件全漏了 | 想想"最奇怪的数据"也测 |

| assert不写错误信息 | 只看到AssertionError不知道为啥 | `assert x > 0, "x必须大于0"` |

| 测试和生产用不同的逻辑 | 测试过了,上线挂了 | 测试要测真实的函数 |

────────────────────────────────────────

> **你有"查Bug查到崩溃"的经历吗?评论区讲讲**

> **收藏+点赞,下篇学面向对象**

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/25 21:18:13

MCP16311/2开关电源设计实战:从元件选型到PCB布局避坑指南

1. 项目概述&#xff1a;从芯片到系统&#xff0c;构建一个可靠的开关电源当你拿到一颗像MCP16311/2这样的同步降压控制器&#xff0c;准备开始设计一个开关电源时&#xff0c;心里想的可能不仅仅是“让它工作”。更实际的问题是&#xff1a;如何确保它在满载时不会过热&#x…

作者头像 李华
网站建设 2026/6/25 21:16:59

AI治理三大陷阱:责任虚化、验证缺位与演进失盲

1. 项目概述&#xff1a;这不是技术故障&#xff0c;而是治理断层“董事会还在犯这3个AI治理错误”——这个标题一出来&#xff0c;我就在好几个闭门研讨会上听到同行摇头。不是因为大家不重视AI&#xff0c;恰恰相反&#xff0c;92%的标普500企业董事会去年都新增了AI相关议程…

作者头像 李华
网站建设 2026/6/25 21:13:34

【STM32HAL库开发】学习笔记(1)——GPIO

1.引脚通用功能与复用功能通过直接控制单片机引脚输出高/低电平或者读取引脚高/低电平状态的方式叫做引脚的通用功能。除此之外的功能称为引脚的复用功能&#xff0c;这些复用功能可以给其他模块进行使用&#xff0c;如UART串口、TIM定时器等。2.引脚复用重映射在实际使用过程中…

作者头像 李华
网站建设 2026/6/25 21:04:18

AlienFX Tools深度指南:从灯光控制到系统优化的全面解决方案

AlienFX Tools深度指南&#xff1a;从灯光控制到系统优化的全面解决方案 【免费下载链接】alienfx-tools Alienware systems lights, fans, and power control tools and apps 项目地址: https://gitcode.com/gh_mirrors/al/alienfx-tools AlienFX Tools是一套用于控制A…

作者头像 李华