Python unittest模块
unittest 是 Python 标准库的单元测试框架,支持测试组织、断言和报告。
基本测试类
Python
import unittest
class MathTest(unittest.TestCase):
def test_add(self):
self.assertEqual(1 + 1, 2)
def test_subtract(self):
self.assertEqual(5 - 3, 2)
def test_multiply(self):
self.assertEqual(2 * 3, 6)
def test_divide(self):
self.assertEqual(6 / 2, 3)
if __name__ == '__main__':
unittest.main()
常用断言方法
Python
import unittest
class AssertionTest(unittest.TestCase):
def test_equal(self):
self.assertEqual(1 + 1, 2) # 相等
self.assertNotEqual(1 + 1, 3) # 不相等
def test_boolean(self):
self.assertTrue(1 == 1) # True
self.assertFalse(1 == 2) # False
def test_comparison(self):
self.assertGreater(5, 3) # 大于
self.assertLess(3, 5) # 小于
self.assertGreaterEqual(5, 5) # 大于等于
self.assertLessEqual(3, 5) # 小于等于
def test_in(self):
self.assertIn(1, [1, 2, 3]) # 包含
self.assertNotIn(4, [1, 2, 3]) # 不包含
def test_type(self):
self.assertIsInstance(1, int) # 类型检查
self.assertNotIsInstance(1, str)
def test_none(self):
self.assertIsNone(None) # None检查
self.assertIsNotNone(1)
setUp 和 tearDown
Python
import unittest
class ResourceTest(unittest.TestCase):
def setUp(self):
# 每个测试前执行
self.resource = create_resource()
print("setUp: 创建资源")
def tearDown(self):
# 每个测试后执行
release_resource(self.resource)
print("tearDown: 释放资源")
def test_use_resource(self):
# 使用 setUp 创建的资源
result = self.resource.process()
self.assertEqual(result, 'success')
def create_resource():
return {'process': lambda: 'success'}
def release_resource(r):
pass
setUpClass 和 tearDownClass
Python
import unittest
class DatabaseTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
# 所有测试前执行一次
cls.db = connect_database()
print("setUpClass: 连接数据库")
@classmethod
def tearDownClass(cls):
# 所有测试后执行一次
cls.db.close()
print("tearDownClass: 关闭数据库")
def test_query(self):
result = self.db.query("SELECT 1")
self.assertIsNotNone(result)
def connect_database():
class MockDB:
def query(self, sql):
return sql
def close(self):
pass
return MockDB()
测试套件
Python
import unittest
class TestA(unittest.TestCase):
def test_a1(self):
self.assertEqual(1, 1)
class TestB(unittest.TestCase):
def test_b1(self):
self.assertEqual(2, 2)
# 创建测试套件
suite = unittest.TestSuite()
suite.addTest(TestA('test_a1'))
suite.addTest(TestB('test_b1'))
# 运行套件
runner = unittest.TextTestRunner()
runner.run(suite)
# 使用 TestLoader
loader = unittest.TestLoader()
suite = loader.loadTestsFromTestCase(TestA)
suite.addTests(loader.loadTestsFromTestCase(TestB))
测试发现
Python
import unittest
# 发现所有测试
loader = unittest.TestLoader()
suite = loader.discover('tests', pattern='test_*.py')
runner = unittest.TextTestRunner()
runner.run(suite)
# 命令行发现
# python -m unittest discover tests
异常测试
Python
import unittest
class ExceptionTest(unittest.TestCase):
def test_raises_exception(self):
# 测试异常
with self.assertRaises(ValueError):
raise ValueError("错误")
def test_exception_message(self):
# 检查异常消息
with self.assertRaises(ValueError) as context:
raise ValueError("错误消息")
self.assertEqual(str(context.exception), "错误消息")
跳过测试
Python
import unittest
class SkipTest(unittest.TestCase):
@unittest.skip("跳过此测试")
def test_skip(self):
self.assertEqual(1, 2) # 不会执行
@unittest.skipIf(True, "条件跳过")
def test_skip_if(self):
pass
@unittest.skipUnless(False, "除非条件满足")
def test_skip_unless(self):
pass
@unittest.expectedFailure
def test_expected_failure(self):
self.assertEqual(1, 2) # 预期失败
断言方法汇总
| 方法 | 说明 |
|---|---|
| assertEqual(a, b) | a == b |
| assertNotEqual(a, b) | a != b |
| assertTrue(x) | x is True |
| assertFalse(x) | x is False |
| assertIs(a, b) | a is b |
| assertIsNone(x) | x is None |
| assertIn(a, b) | a in b |
| assertIsInstance(a, b) | isinstance(a, b) |
| assertRaises(exc) | 抛出异常 |
命令行运行
Bash
# 运行单个测试模块
python -m unittest test_module
# 运行单个测试类
python -m unittest test_module.TestClass
# 运行单个测试方法
python -m unittest test_module.TestClass.test_method
# 详细输出
python -m unittest -v test_module
要点总结
- TestCase 是测试类基类,测试方法以 test_ 开头
- setUp/tearDown 每个测试前后执行
- setUpClass/tearDownClass 类级别一次性执行
- 断言方法验证测试结果
- TestSuite 组织多个测试
- TestLoader 自动发现和加载测试
@unittest.skip跳过测试assertRaises测试异常抛出-m unittest命令行运行测试
📝 发现内容有误?点击此处直接编辑