unittest
unittest库是python自带的,直接 import unittest
导入即可,在使用时需遵守几条规则:
1.创建的类必须继承
unittest.TestCase
类
2.所有的测试用例方法命名必须以test
开头
四大组件:
- 前置后置条件
- 断言机制
- 测试用例
- 测试套件与运行器
1. 前置后置条件
setUpModule/tearDownModule:在整个模块的开始与结束时被执行。
setUpClass/tearDownClass:在测试类的开始与结束时被执行
setUp/tearDown:在测试用例的开始与结束时被执行。
# -*- coding: utf-8 -*-
# @Time : 2024/2/5 14:09
# @Author : 居里夫人吃橘子
# @File : demo01.py
# @Software: PyCharm
import unittest
class Demo01(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
print('这是setUpClass前置条件')
@classmethod
def tearDownClass(cls) -> None:
print('这是tearDown后置条件')
def test_01(self):
print('这是test01测试用例')
def test_02(self):
print('这是test02测试用例')
if __name__ == '__main__':
unittest.TestCase()
需要注意的是,setUpClass/tearDownClass 为类方法,需要通过@classmethod 进行装饰。另外,方法的参数为 cls。
2. 断言
断言方法 | 断言描述 | 备注 |
---|---|---|
assertEqual(a, b, msg=None) | 验证a=b,不等则fail | msg为可选参数 |
assertNotEqual(a, b,msg=None) | 验证a!=b,相等则fail | |
assertTrue(x,msg=None) | 验证x为True,如果是false,则fail | |
assertFalse(x,msg=None) | 验证x为false,如果是true,则fail | |
assertIs(a, b,msg=None) | 验证a和b是同一个对象 | |
assertIsNot(a, b,msg=None) | 验证a和b不是同一个对象 | |
assertIsNone(x,msg=None) | 验证x是None | |
assertIsNotNone(x,msg=None) | 验证x不是None | |
assertIn(a, b,msg=None) | 验证a in b | |
assertNotIn(a, b,msg=None) | 验证a is not b | |
assertIsInstance(a, b,msg=None) | 验证a是b的实例 | |
assertNotIsInstance(a, b,msg=None) | 验证a不是b的实力 |
3. 测试用例
测试用例的方法名和文件名必须以test_
开头,非test_开头的方法则不会被运行;
测试用例的运行顺序为: 0-9,A-Z,a-z的顺序
import unittest
class Demo01(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
print('这是setUpClass前置条件')
@classmethod
def tearDownClass(cls) -> None:
print('这是tearDown后置条件')
def test_01(self):
print('这是test01测试用例')
def test_02(self):
print('这是test02测试用例')
def sum(self):
a = 1
b = 2
print(a+b)
if __name__ == '__main__':
unittest.TestCase()
设计测试用例时,用例之间的关联系要尽可能的降低,如需要在test_02中使用test_01用例中的数据,可以把数据传到setUpClass(cls)
下,在test_02通过类名.变量名
获取;
import unittest
from unittest import skip, skipIf
class UnitDemo(unittest.TestCase):
def setUpClass(cls) -> None:
print('这是setUpClass前置条件')
cls.status = 0
@classmethod
def tearDownClass(cls) -> None:
print('这是tearDown后置条件')
def test_01(self):
print('这是test01测试用例')
print('入库成功')
print(self.status)
UnitDemo.status = 1
print(self.status)
def test_02(self):
print('这是test02测试用例')
#获取上一个测试用例运行后的数据
print(self.status)
def test_03(self):
print('这是test03测试用例')
def sum_test(self):
a = 1
b = 2
print(a + b)
if __name__ == '__main__':
unittest.TestCase()
skip装饰器:
# -*- coding: utf-8 -*-
# @Time : 2024/2/5 17:09
# @Author : 居里夫人吃橘子
# @File : skip_demo.py
# @Software: PyCharm
import unittest
class SkipTest(unittest.TestCase):
@unittest.skip("直接跳过")
def test_01(self):
print('第1条测试用例')
@unittest.skipIf(1 == 1, '条件为True的跳过')
def test_02(self):
print('第2条测试用例')
@unittest.skipUnless(1 == 2, '条件不为True跳过')
def test_03(self):
print('第3条测试用例')
# 不管结果为啥都标记用例结果直接为失败
@unittest.expectedFailure
def test_04(self):
print('第4条测试用例')
if __name__ == '__main__':
unittest.TestCase()
测试套件
测试套件专门用例管理所有的测试用例类,需要注意套件的使用一定是重新建立一个py文件进行调用,使用 unittest.TestSuite
类来进行使用,使用套件执行用例可以自定义用例执行的顺序;
- 基于用例名称添加测试用例,可以添加不同模块的测试用例
import unittest
from selenium_class02.test_demo01 import Demo01
# 创建测试套件
suite = unittest.TestSuite()
# 基于用例名称添加
suite.addTest(Demo01('test_02'))
suite.addTest(Demo01('test_01'))
# 通过运行器运行测试用例
run = unittest.TextTestRunner(verbosity=2)
run.run(suite)
- 基于用例名称添加,以list形式
import unittest
from selenium_class02.test_demo01 import Demo01
suite = unittest.TestSuite()
# 基于用例名称添加
# suite.addTest(Demo01('test_02'))
# suite.addTest(Demo01('test_01'))
# 基于用例名称进行添加,以list形式
cases = [Demo01('test_02'), Demo01('test_01')]
suite.addTests(cases)
# verbosity表示日志的输出级别
run = unittest.TextTestRunner(verbosity=2)
run.run(suite)
- 基于整个class进行添加,会添加这个类中的所有测试用例;
# 通过添加一个完整的class进入套件
suite.addTests(unittest.TestLoader().loadTestsFromTestCase(Demo01))
- 添加py文件进入套件;
# 定义用例的获取路径
path = './'
# 添加py文件进入套件
discover = unittest.defaultTestLoader.discover(start_dir=path, pattern='test*.py')
# 创建运行器
run = unittest.TextTestRunner(verbosity=2)
# run.run(suite)
run.run(discover)
HTMLTestRunner
HTMLTestRunner测试报告:本质意义而言,其实就是一个运行器。
环境部署:下载py文件到python安装路径中的Lib文件下;默认只支持2.7版本以下,要支持3以上的版本,需要修改源码;
HTMLTestRunner是英文版本,HTMLTestReportCN是中文版本
# -*- coding: utf-8 -*-
# @Time : 2024/2/5 17:23
# @Author : 居里夫人吃橘子
# @File : suit_test.py
# @Software: PyCharm
import os
import unittest
from HTMLTestReportCN import HTMLTestRunner
suite = unittest.TestSuite()
# 定义用例的获取路径
path = './'
# 添加py文件进入套件
discover = unittest.defaultTestLoader.discover(start_dir=path, pattern='test*.py')
# HTMLTestRunner生成测试报告
# 配置测试报告
report_dir = './report/' # 保存路径
report_title = '测试报告' # 报告名称
report_description = '这是测试报告中的描述部分' # 测试报告描述
report_file = report_dir + 'report1.html' # 测试报告的文件,因为是需要给文件中写入的所以需要指定文件的路径
# 测试执行者
report_tester = 'kk'
# 保存报告的路径是否存在,不存在则创建一个
if not os.path.exists(report_dir):
os.mkdir(report_dir)
# 生成测试报告,其实就是写入一个文件内容
with open(report_file, 'wb') as file:
runner = HTMLTestRunner(stream=file, title=report_title,
description=report_description, verbosity=2, tester=report_tester)
runner.run(discover)
BeautifulReport
# 环境部署
pip install beautifulreport
代码示例:
import time
import unittest
from BeautifulReport import BeautifulReport
if __name__ == '__main__':
# 约定时间戳的格式,注意在Windows中文件的路径不能存在 < > : " / \ | ? *
strf_time_str = time.strftime("%Y-%m-%d %H-%M-%S")
file_name = f'测试报告_{strf_time_str}'
# 测试报告存放路径
paths = r'D:\PythonTest\Study\selenium_class02\reports'
# 创建套件
# 在python中 . 表示从当前运行的文件作为当前目录
discover = unittest.defaultTestLoader.discover(start_dir='./', pattern='test*.py')
result = BeautifulReport(discover)
result.report(filename=file_name , description='测试报告', log_path=paths)