第1章:测试框架入门——unittest框架基础、TestCase类、测试方法命名规范、测试运行器
各位同学,咱们今天聊聊Python里最经典的测试框架——unittest。
说实话,我刚开始做测试开发那会儿,市面上还没这么多花里胡哨的框架。unittest就是那个“老大哥”,稳得很。直到现在,我在很多企业级项目里,依然首选它。为什么?因为它够简单、够稳定、够原生。
1.1 unittest框架是什么?
unittest是Python标准库自带的单元测试框架。说白了,就是Python官方给你准备好的测试工具箱。你不需要装任何第三方包,直接import unittest就能用。
我个人习惯把它比作“测试界的乐高”。框架搭好了基础结构,你只需要往里面填自己的测试逻辑就行。
核心三要素:
- TestCase类——你的测试代码要写在继承它的类里
- 测试方法——以
test_开头的方法,框架会自动识别并执行 - 测试运行器——负责调度和执行测试的工具
我在项目中遇到过不少新手,上来就写一堆函数,然后手动调用。嗯,这样也能跑,但维护起来简直噩梦。用unittest,你的测试就有了统一的“身份证”。
1.2 TestCase类——测试的基石
TestCase是unittest的核心类。你的所有测试逻辑,都要放在继承它的子类里。
来看一个最简单的例子:
import unittest
class TestMathOperations(unittest.TestCase):
def test_addition(self):
result = 1 + 1
self.assertEqual(result, 2)
def test_subtraction(self):
result = 5 - 3
self.assertEqual(result, 2)
if __name__ == '__main__':
unittest.main()
你看,就这么几行,一个完整的测试就出来了。为什么这么设计?你想想看,如果每个测试都是独立的类和方法,那管理和扩展就方便多了。
我的小建议:
每个TestCase类最好只测试一个功能模块。比如TestUserLogin只测登录,TestUserRegister只测注册。别把所有测试塞到一个类里,那样后期你会想哭的。
1.3 测试方法命名规范——名字就是文档
这一点我特别想强调。很多同学觉得命名无所谓,随便写个test1、test2就完事了。我曾经接手过一个项目,里面全是test_a、test_b这种名字……嗯,那感觉就像看天书。
unittest要求测试方法必须以test_开头。但光有这个还不够,我建议你遵循以下规范:
| 命名模式 | 示例 | 说明 |
|---|---|---|
| test_功能_场景 | test_login_success |
测试登录成功场景 |
| test_功能_异常 | test_login_wrong_password |
测试密码错误场景 |
| test_功能_边界 | test_input_max_length |
测试输入最大长度边界 |
说白了,好的命名就是最好的注释。别人一看方法名,就知道这个测试在测什么、测什么场景。
避坑指南:
我曾经见过有人把测试方法命名为test_1、test_2……结果跑测试时,执行顺序完全不是他想的。因为unittest默认按ASCII码排序执行方法名。所以,test_10会在test_2之前执行。嗯,这坑我踩过。
1.4 测试运行器——让测试跑起来
测试写好了,怎么跑?这就轮到测试运行器登场了。
unittest提供了几种运行方式:
- 命令行运行:
python -m unittest test_module.py - 代码中运行:调用
unittest.main() - 发现模式:
python -m unittest discover,自动查找所有测试文件
我个人最常用的是发现模式。为什么呢?因为项目大了以后,测试文件会散落在各个目录。用discover,框架会自动帮你找到所有以test开头的文件,然后一股脑全跑了。
来看一个实际项目中的目录结构:
project/
├── tests/
│ ├── test_login.py
│ ├── test_register.py
│ └── test_logout.py
└── run_tests.py
在run_tests.py里,你可以这样写:
import unittest
if __name__ == '__main__':
loader = unittest.TestLoader()
suite = loader.discover('tests', pattern='test_*.py')
runner = unittest.TextTestRunner(verbosity=2)
runner.run(suite)
这样,不管你有多少个测试文件,一行命令全搞定。是不是很爽?
我的经验:
verbosity参数控制输出详细程度。设为0只显示结果,设为1显示点号,设为2显示每个测试方法名。我建议调试时用2,正式跑CI时用1。别问为什么,问就是日志太多CI会报警。
1.5 本章知识体系总览
为了让你更直观地理解unittest的核心结构,我画了一张图:
这张图清晰地展示了unittest的执行流程:测试运行器通过发现模式找到所有测试文件,组装成测试套件,然后逐个执行TestCase中的测试方法。嗯,就是这么个流程。
1.6 写在最后
unittest虽然看起来简单,但它是所有测试框架的根基。你以后学pytest、nose,会发现它们很多设计思路都来自unittest。所以,把这一章吃透,后面的路就好走了。
记住三个核心:TestCase是容器,test_是规矩,运行器是引擎。这三样搞明白了,unittest你就入门了。
可可精品资料库