▼点击下方卡片关注我
▲点击上方卡片关注我
要想写出靠谱的代码,单元测试就必不可少。真要说起来,咱们写代码就跟盖房子一样,单元测试就好比是房子的质量检测,每个砖块都得过关才行。Python标准库里的 unittest模块 就是一个特别好使的测试工具,今天咱们就一起来研究研究怎么用它来保证代码质量。
单元测试基本概念
单元测试说白了就是测试代码里最小的功能单元。比方说你写了个函数,那就得测测这个函数在各种情况下是不是都能正常工作。这么干有啥好处呢?bug早发现早治疗,代码重构也不怕改出问题。
来看个最基础的例子:
1
# calculator.py
2
def add(a, b):
3
return a + b
5
def divide(a, b):
6
return a / b
对应的测试代码:
1
# test_calculator.py
2
import unittest
3
from calculator import add, divide
5
class TestCalculator(unittest.TestCase):
6
def test_add(self):
7
# 测试正数相加
8
self.assertEqual(add(1, 2), 3)
9
# 测试负数相加
10
self.assertEqual(add(-1, -1), -2)
12
def test_divide(self):
13
# 测试正常除法
14
self.assertEqual(divide(6, 2), 3)
15
# 测试除数为0的情况
16
with self.assertRaises(ZeroDivisionError):
17
divide(1, 0)
19
if __name__ == '__main__':
20
unittest.main()
⚠️ 小贴士:
测试方法名必须以test开头
每个测试用例要够独立,不能互相影响
测试要考虑边界条件和异常情况
断言方法大盘点
unittest提供了一堆好使的断言方法,这些都是测试武器库里的必备神器:
1
def test_assertions(self):
2
# 判断相等
3
self.assertEqual(1 + 1, 2)
5
# 判断是否为True/False
6
self.assertTrue(isinstance(1, int))
7
self.assertFalse(2 > 3)
9
# 判断是否包含
10
self.assertIn(3, [1, 2, 3])
12
# 判断是否为None
13
self.assertIsNone(None)
测试夹具setUp和tearDown
有时候测试前要准备环境,测试后要清理现场,这时候就用得上这两个法宝了:
1
class TestDatabase(unittest.TestCase):
2
def setUp(self):
3
# 测试前创建数据库连接
4
self.db = Database()
5
self.db.connect()
7
def tearDown(self):
8
# 测试后关闭连接
9
self.db.close()
11
def test_query(self):
12
result = self.db.execute(“SELECT * FROM users”)
13
self.assertIsNotNone(result)
⚠️ 小贴士:
setUp在每个测试方法前都会执行一次
tearDown即使测试失败也会执行
数据库、文件操作记得在tearDown里清理
跳过测试和预期失败
代码改着改着,有些测试可能暂时跑不通,这时候可以暂时跳过:
1
class TestFeatures(unittest.TestCase):
2
@unittest.skip(“暂时还没实现这个功能”)
3
def test_new_feature(self):
4
pass
6
@unittest.expectedFailure
7
def test_known_bug(self):
8
# 这个测试预期会失败
9
self.assertEqual(1/0, 1)
跟数据库这种外部系统打交道的测试,最好用mock来模拟,省事又靠谱:
1
from unittest.mock import patch
3
class TestUser(unittest.TestCase):
4
@patch('myapp.database.query')
5
def test_get_user(self, mock_query):
6
mock_query.return_value = {“id”: 1, “name”: “张三”}
7
user = get_user(1)
8
self.assertEqual(user['name'], “张三”)
⚠️ 小贴士:
mock对象要模拟原始对象的所有必要行为
mock记得验证是否被正确调用
复杂的mock考虑用fixture来管理
写单元测试就是给代码上保险,多花点时间写测试,后面省心不少。代码改动时跑跑测试,哪里出问题一目了然。不过也别太死板,测试代码的投入要跟业务价值匹配,关键的核心逻辑一定要好好测。
往期回顾
点赞分享
让钱和爱流向你