unittest框架断言和参数化
一、断言
让程序代替人为判断测试程序执行结果是否符合预期结果的过程
断言方法:
assertEqual(预期结果,实际结果)
import unittest #创建测试类 class Test_1(unittest.TestCase): def test_001(self): self.assertEqual(10,10) #用例通过 def test_001(self): self.assertEqual(10,11) #用例不通过 def test_003(self): self.assertIn("admin","欢迎adminnnnnn") #包含,通过 self.assertIn("admin", "欢迎addddminnnnnn") #不包含完整admin,不通过
二、参数化
通过参数的方式来传递数据,从而实现数据和脚本的分离。并且可以实现用例的重复执行。
unittest本身不支持参数化,通过安装 parameterized 来实现。
组织测试数据,格式 [(),(),()] ,一个元组就是一组测试数据。
参数化:在测试方法上使用装饰器,@parameterized . expand(测试数据)
from parameterized import parameterized #导入参数化包 from add_01 import add_001 #导入函数测试方法 import unittest #导入测试数据 data = [(1,2,3),(1,1,2),(4,5,9)] #如果数据是另一个文件包 from explain_data import build_add_data #创建测试类 class Test_1(unittest.TestCase): @parameterized.expand(data) #参数化 def test_add(self,a,b,expect): self.assertEqual(expect,add_001(a,b)) #从外部导入数据 @parameterized.expand(build_add_data()) # 参数化 def test_add(self, a, b, expect): self.assertEqual(expect, add_001(a, b))
import json def build_add_data(): with open("001.json") as f: data = json.load(f) #此时直接为[[],[],[]]列表模式 return data def build_add_data_1(): with open("001.json") as f: data_list = json.load(f) #此时为字典格式[{},{},{}] for data in data_list: data_01 = [] a = data.get("a") b = data.get("b") expect = data.get("expect") data_01.append((a,b,expect)) return data_01
三、生成测试报告
生成测试报告,执行套件,后接着在本文件夹生成测试报告
import unittest from htmltestreport import HTMLTestReport from test_001 import Test_1 #套件 suite = unittest.TestSuite() suite.addTest(unittest.makeSuite(Test_1)) #运行对象 #runner = HTMLTestReport(报告文件的路径.html,报告的标题,其他描述信息) runner = HTMLTestReport("test_add_report.html","加法测试用例报告","xxx") runner.run(suite)
四、绝对路径的使用
1、绝对路径
runner = HTMLTestReport("./report/test_add_report.html","加法测试用例报告","xxx")
绝对路径方法:
1. 在项目的根目录,创建一个 Python 文件(app.py 或者 config.py)
2. 在这个文件中 获取项目的目录,在其他代码中使用 路径拼接完成绝对路径的书写
在项目的根目录,创建一个 Python 文件(app.py 或者 config.py) ,然后拼接在其他文件要是用的路径使用即可
import os # __file__ 特殊的变量,表示当前代码文件名 # path1 = os.path.abspath(__file__) # print(path1) # path2 = os.path.dirname(path1) # print(path2) # BASE_DIR = os.path.dirname(os.path.abspath(__file__)) BASE_DIR = os.path.dirname(__file__)
实际练习:
1, 对登录函数进行测试, 登录函数 定义在 tools.py 中
2, 在 case 目录中书写用例对login 函数进行测试, 使用断言
3, 将 login 函数的测试数据定义在 json 文件中,完成参数化, data 目录中
4, 生成测试报告 report 目录中
tools.py
def login(username, password):
if username == 'admin' and password == '123456':
return '登录成功'
else:
return '登录失败'
测试数据
[ { "desc": "正确的用户名和密码", "username": "admin", "password": "123456", "expect": "登录成功" },
{ "desc": "错误的用户名", "username": "root", "password": "123456", "expect": "登录失败" },
{ "desc": "错误的密码", "username": "admin", "password": "123123", "expect": "登录失败" },
{ "desc": "错误的用户名和密码", "username": "root", "password": "123123", "expect": "登录失败" } ]
读取测试数据
def build_login_data():
with open(BASE_DIR + '/data/login_data.json', encoding='utf-8') as f:
data_list = json.load(f) # [{}, {}] ---> [()]
new_list = []
for data in data_list: # 字典中的 desc 不需要
username = data.get('username')
password = data.get('password')
expect = data.get('expect')
new_list.append((username, password, expect))
return new_list
测试用例代码
import unittest
from common.read_data import build_login_data
from tools import login
from parameterized import parameterized
class TestLogin(unittest.TestCase):
@parameterized.expand(build_login_data())
def test_login(self, username, password, expect):
print(f'username: {username}, password: {password},expect: {expect}')
self.assertEqual(expect, login(username, password))
生成报告
import unittest
from app import BASE_DIR
from case.test_login import TestLogin
from htmltestreport import HTMLTestReport
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestLogin))
runner = HTMLTestReport(BASE_DIR + '/report/login_report.html', '登录测试报告', 'V1.0')
runner.run(suite)
五、跳过
跳过:对于一些未完成的或者不满足测试条件的测试函数和测试类,可以跳过执行(简单来说, 不想执行的测试方法,可以设置为跳过)
1、使用
- 直接将测试函数标记成跳过
@unittest.skip('跳过的原因')
- 根据条件判断测试函数是否跳过
@unittest.skipIf(判断条件, reason='原因') # 判断条件为 True, 执行跳过
2、代码演示
import unittest
version = 29
class TestSkip(unittest.TestCase):
@unittest.skip('没什么原因,就是不想执行')
def test_1(self): print('方法一')
@unittest.skipIf(version >= 30, '版本号大于等于 30, 测方法不用执行')
def test_2(self): print('方法二')
def test_3(self): print('方法三')
if __name__ == '__main__':
unittest.main()
再结合上面的代码用例执行即可