unittest 基础教程
unittest 单元测试框架是受到 JUnit 的启发,与其他语言中的主流单元测试框架有着相似的风格。其支持测试自动化,配置共享和关机代码测试。支持将测试样例聚合到测试集中,并将测试与报告框架独立。
官方文档:https://docs.python.org/zh-cn/3/library/unittest.html
编写规则:
-
测试模块首先 import unittest
-
测试类必须继承 unittest.TestCase
-
测试方法必须以 test_ 开头
unittest 核心组成
Test Fixture
Test Fixture 通常用来做测试用例的准备或者清理工作。比如测试开始前的数据准备或者测试结束后的数据清理等。Python 通过 setUp()、tearDown()、setUpClass()、tearDownClass() 这 4 个钩子函数(Hook)来实现测试的准备和清理工作。
Test Case
Test Case 是 unittest 的最小单元,一个 Test Case 就是一个测试用例,通常 Test Case 会继承 TestCase 这个基类。
Test Suite
Test Suite 是测试套件,就是我们常说的测试用例集,它可以包含一个或多个测试用例。
Test Loader
Test Loader 用来从提供的类(classes)和模块(modules)中生成测试用例集,默认情况下unittest 会提供一个 default test loader。
Test Runner
Test Runner 是测试执行器,用来进行测试用例的执行和测试结果的输出。
unittest 运行原理
-
Test Cases 包括一个或者多个 TestCase 类,其中保存了具体的测试过程,你可以在测试类里使用 Test Fixture,例如setUp()、tearDown() 进行测试开始前的准备和结束后的清理工作。
-
TestSuite 包括一个或者多个 TestSuite 类,其中 TestSuite 包括了一个或多个 TestCase,也可以包括其他 TestSuite。TestSuite 通过 addTest() 或者 addTests() 方法把一个个的测试用例或者测试用例集(TestSuite)组装起来成为一个新的测试用例集。
-
TestLoader 类加载本地或从外部文件中定义好的 TestCase 或者 TestSuites。
-
TestRunner 包括TextTestRunner类, 它提供了运行测试的标准平台。测试运行可以通过 unittest.main() 或者 python -m unittest xxx.py 来运行。
-
Test Results Collector 包括 TestResults 类,它为测试结果提供了一个标准容器,它存储运行的测试用例状态,例如 errors、failures、skipped,测试的结果可以直接在 Console 输出,也可以为通过其他形式输出,例如 Text、result、output。
unittest 的使用
简单入门
# coding=utf-8
import unittest
# 测试类必须要继承TestCase类
class TestSample(unittest.TestCase):
# 测试用例默认以test_开头
def test_equal(self):
self.assertEqual(1, 1)
def test_not_equal(self):
self.assertNotEqual(1, 0)
if __name__ == '__main__':
unittest.main()
TestFixture 的使用
如果你想在测试用例或者测试用例集开始前,执行某些操作, 在测试用例或者测试用例集结束后再执行另外一些操作,那么你应该使用 Test Fixture。
# coding=utf-8
import unittest
# 测试类必须要继承TestCase类
class TestSample(unittest.TestCase):
#类共享的fixture,在整个测试类执行过程中仅仅执行一次,需加装饰器@classmethod
@classmethod
def setUpClass(cls):
print('整个测试类只执行一次 -- Start')
#测试用例fixture
def setUp(self):
print('每个测试开始前执行一次')
# 测试用例默认以test开头
def test_equal(self):
self.assertEqual(1, 1)
def test_not_equal(self):
self.assertNotEqual(1, 0)
#测试用例fixture
def tearDown(self):
print('每个测试结束后执行一次')
#类共享的fixture,在整个测试类执行过程中仅仅执行一次,需加装饰器@classmethod
@classmethod
def tearDownClass(cls):
print('整个测试类只执行一次 -- End')
if __name__ == '__main__':
unittest.main()
TestFixture 包括如下 4 个方法:
- setUp()
setUp()方法在每一个测试用例执行测试前都会执行。
- setUpClass()
setUpClass()方法仅在整个测试类开始执行前执行.setUpClass()方法必须使用 @classmethod 来装饰。
setUp() 和 setUpClass() 通常用来进行测试前的准备工作。例如,访问数据库获得测试用例需要的数据等。
- tearDown()
tearDown()方法在每一个测试用例执行后都会执行。
- tearDownClass()
tearDownClass()方法仅在整个测试类结束执行后执行.tearDownClass()方法必须使用 @classmethod 来装饰。
tearDown() 和 tearDownClass() 通常用来进行测试后的清理工作。例如,测试结束后删除测试产生的数据,将被测试系统恢复至之前的状态等。
unittest 断言
程序执行到断言位置时,对应断言应为真;若不为真,则中止执行,给出错误信息。所有断言方法都有一个msg参数,如果指定msg参数的值,则将该信息作为失败的错误信息返回。
常用断言方法:
序号 | 断言方法 | 断言描述 |
---|---|---|
1 | assertEqual(arg1, arg2, msg=None) | 验证arg1 == arg2,不等则fail |
2 | assertNotEqual(arg1, arg2, msg=None) | 验证arg1 != arg2,相等则fail |
3 | assertTrue(arg1, arg2, msg=None) | 验证 expr 是 true,否则 fail |
4 | assertFalse(arg1, arg2, msg=None) | 验证 expr 是 false,否则 fail |
unittest 执行测试用例
执行全部测试用例
if __name__ == '__main__':
unittest.main()
unittest.main(module='__main__', defaultTest=None, argv=None, testRunner=None, testLoader=unittest.defaultTestLoader, exit=True, verbosity=1, failfast=None, catchbreak=None, buffer=None, warnings=None
其各个参数的含义如下:
-
module:指定待运行的 module,默认是“main”;
-
defaultTest:单个测试的名字或者多个测试名字的组合(必须要 iterable);
-
argv:传递给程序的一组变量,如果没有指定,那么系统默认使用 sys.argv;
-
testRunner:指定 unittest 的 test runner,可以是 test runner 类本身或者 test runner 类实例。默认情况下,main 函数会调用 sys.exit(),并且会在屏幕上显示测试运行错误或者成功的提示;
-
testLoader:必须是 TestLoader 类实例,默认是 defaultTestLoader;
-
exit:默认是 True,即测试运行完调用 sys.exit(),在交互模式下使用时可指定为 False;
-
verbosity:用于控制显示在 console 里的 log 等级,有 0、1、 2 三种,一般默认为等级 1,其中等级 2 显示的 log 最详细。
按需执行测试类中的测试方法
假设项目结构如下:
|--qiaoTest
|--tests
|--test_to_run.py
|--yetest.py
|--__init__.py
|--main.py
|--__init__.py
# coding=utf-8
import unittest
from tests.test_to_run import TestToRun
from tests.yetest import YeTest
if __name__ == '__main__':
#定义一个测试用例集
suite = unittest.TestSuite()
#把测试类下的测试方法加入用例集
suite.addTest(TestToRun('test_run'))
suite.addTest(YeTest('test_ye'))
#指定runner为TestTextRunner
runner = unittest.TestTextRunner(verbosity=2)
#执行测试
runner.run(suite)
执行测试类
#定义一个测试用例集
suites = unittest.TestSuite()
#把测试类加入用例集
suite1 = unittest.TestLoader().loadTestsFromTestCase(TestMethod1)
suite2 = unittest.TestLoader().loadTestsFromTestCase(TestMethod2)
suites.addTest(suite1)
suites.addTest(suite2)
#指定runner为TestTextRunner
runner = unittest.TextTestRunner(verbosity=2)
#执行测试
runner.run(suites)
执行py测试文件
#定义一个测试用例集,执行test_dir路径下所有py文件
suite = unittest.defaultTestLoader.discover(test_dir, pattern='*.py')
#指定runner为TestTextRunner
runner = unittest.TextTestRunner(verbosity=2)
#执行测试
runner.run(suite)
忽略测试用例
unittest 还支持忽略执行某些测试用例,只要在要忽略的测试用例上加上如下装饰器即可:
-
@unittest.skip() 执行时直接忽略掉被装饰的测试用例;
-
@unittest.skipIf() 如果 skipIf 里的条件成立,执行时直接忽略掉被装饰的测试用例;
-
@unittest.skipUnless() 永久在执行时忽略被装饰的测试用例,除非 skipUnless 里的条件成立;
-
@unittest.expectedFailure 期望被装饰的测试用例是失败的,如果是失败的,则此条测试用例将被标记为测试通过。
# coding=utf-8
import unittest
flag = False
# 测试类必须要继承TestCase类
class ITestingTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
print('整个测试类只执行一次 -- Start')
def setUp(self):
print('每个测试开始前执行一次')
@unittest.skip('没有任何原因,忽略运行')
def equal_test(self):
self.assertEqual(1, 1)
@unittest.skipIf(flag == True, "flag为True则skip")
def test_not_equal(self):
self.assertNotEqual(1, 0)
@unittest.skipUnless(flag == True, "flag为False则skip")
def test_not_equal1(self):
self.assertNotEqual(1, 0)
@unittest.expectedFailure
def test_not_equal2(self):
self.assertNotEqual(1, 0)
def tearDown(self):
print('每个测试结束后执行一次')
@classmethod
def tearDownClass(cls):
print('整个测试类只执行一次 -- End')
if __name__ == '__main__':
flag = False
unittest.main(verbosity=2)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具