单元测试用例不是摆设
很多人写代码顺手就跑,功能看着能用就行。可改两行代码,原本正常的逻辑突然崩了,还找不到原因。这时候才想起——哎,要是有单元测试就好了。
单元测试用例其实就是用来验证你写的某个函数、某个方法,在各种情况下能不能正确工作。它不关心整个系统怎么运行,只盯住最小的功能单元。
从一个简单例子说起
比如你写了个计算折扣的函数,原价100,打8折,应该返回80。你总不能每次改完代码都手动输入一遍看结果吧?不如写个测试用例固定下来:
def test_calculate_discount():
result = calculate_discount(100, 0.8)
assert result == 80下次谁动了这个函数,一跑测试就知道有没有出问题。这就是用例的价值——帮你守住底线。
边界情况别漏掉
正常情况能算对,不代表就没问题。用户输个负数价格怎么办?折扣写成1.5(相当于加价)算不算合法?这些边界条件也得覆盖到。
好的测试用例不会只测“理想世界”,而是把各种歪点子都试一遍:
def test_discount_with_negative_price():
result = calculate_discount(-50, 0.9)
assert result is None # 或抛异常
def test_discount_over_100_percent():
result = calculate_discount(100, 1.2)
assert result == 120 # 如果业务允许反向折扣这些case写进去,代码以后不管谁维护,都能知道哪些情况是明确支持或拒绝的。
测试要快,更要独立
有些人在测试里连数据库、调外部API,一跑十几个秒,时间长了大家就不愿意跑了。单元测试应该是轻量的,只测当前函数逻辑,依赖的部分可以用mock模拟。
比如你要测一个下单函数,但不想真发请求到支付接口,就可以伪造一个返回值:
@mock.patch('app.payment_client.charge')
def test_order_processing(mock_charge):
mock_charge.return_value = {'success': True}
result = create_order(amount=99)
assert result.status == 'paid'这样既验证了流程,又不依赖网络,本地一秒跑完几十个用例。
别为了覆盖率硬凑
有些人追求数字好看,拼命写测试把覆盖率刷到90%以上。但写一堆没意义的断言,比如只调用函数不验证结果,其实没啥用。
真正有用的用例,是能发现问题的。哪怕只有5个测试,只要覆盖了核心逻辑和常见坑,就比50个走过场的强。
项目刚起步时,优先给关键模块写用例:用户登录、金额计算、状态流转这些。出了问题影响大,提前卡住最值。
让测试成为习惯
最好是在写代码的同时就把测试写了,也就是所谓的TDD(测试驱动开发)。先想“我希望它怎么被使用”,再写测试,最后补实现。
一开始慢一点,但后期改起来心里有底。就像给房子装了报警器,哪里漏水、短路,马上就能知道。
现在的CI/CD流程基本都支持自动跑测试。提交代码自动触发,失败了直接拦截。这种配置在软件配置管理里配上一次,后面省心很久。