unittest框架
一、单元测试
定义:单元测试就是对单个模块或者是单个类或者是单个函数进行测试
代码版的测试用例,设计测试数据,判断测试结果
手工测试:excel写用例、手工执行用例、人为的判断测试结果、写个测试报告
自动化测试:代码实现的用例、 代码执行用例、代码判断结果、代码生成测试报告
演示案例:登录功能函数
文件名(模块名):loginlx.py
def login_check(username=None,password=None):
if username != None and password !=None:
if username =="zhanghao" and password=="mima":
print("登陆成功!")
return {"code": 0, "msg": "登录成功"}
else:
return {"code": 1, "msg": "账号或密码不正确"}
else:
return {"code": 1, "msg": "账号或密码不能为空"}
根据登录功能简单的列出5条测试用例:
1、账号密码正确
入参:账号python27 密码lemonban
预期结果:{“code”: 0, “msg”: “登录成功”}
实际结果:
2、账号正确,密码错误
入参:账号python27 密码lemonban11
预期结果:{“code”: 1, “msg”: “账号或密码不正确”}
实际结果:
3、账号错误,密码正确,
入参:账号python25 密码lemonban
预期结果:{“code”: 1, “msg”: “账号或密码不正确”}
实际结果:
4、账号为空
入参:账号为空 密码lemonban11
预期结果:{“code”: 1, “msg”: “所以的参数不能为空”}
实际结果:
5、密码为空、
入参:账号Python6 密码为空
预期结果:{“code”: 1, “msg”: “所以的参数不能为空”}
实际结果
下面开始编写登陆功能的测试用例
文件名(模块名):test_case_login.py
from loginlx import login_check
import unittest
class Denglu(unittest.TestCase):
def test_001(self):
res = login_check("zhanghao","mima")
# 断言:实际结果与预期结果的比对
self.assertEqual(res,{"code": 0, "msg": "登录成功"})
def test_002(self):
res = login_check("zhanghao1","mima")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不正确"})
def test_003(self):
res = login_check("zhanghao","mima1")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不正确"})
def test_004(self):
res = login_check("mima")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不能为空"})
def test_005(self):
res = login_check("zhanghao")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不能为空"})
运行后:
pycharm中unittest和pytest运行方式切换:
setting–》Tools–》Python Intergrated Tools
二、unittest框架-四大核心概念
1、用例编写步骤:
1、导入unittest
2、创建一个测试类,继承unittest.TestCase
3、在测试类当中,以test_ 开头,定义测试函数。
每一个test_开头的函数,就是一个测试用例。
4、编写用例:
4.1、测试数据
4.2、测试步骤
4.3、断言:预期结果与实际结果的比对
AssertionError:断言失败-用例失败
assert表达式(True表示通过,False表示失败)
self . assertXXXXX( )
常用的断言方法如下:
方法 | 检查 |
---|---|
assertEqual(a,b) | a==b |
assertNotEqual(a,b) | a!=b |
assertTrue(x) | bool(x) is True |
assertFalse(x) | bool(x) is False |
assertis(a,b) | a is b |
assertisNot(a,b) | a is not b |
assertin(a,b) | a in b |
assertNotin(a,b) | a not in b |
2、收集用例:TestSuite(测试套件),TestLoader加载用例
2.1、测试套件: TestSuite
unittest.TestSuite()
两个方法,不常用,均了解即可:
方法一: addTest(类名(" 用例名"))添加一个测试用例
方法二: addTests([类名(" 用例名"),类名(" 用例名"),类名(" 用例名")]) 添加一个测试用例的列表
run.py代码如下 (与test_case_login和test_case_demo同一目录下)
import unittest
from test_case_login import Denglu
from test_case_demo import Testdemo
# 1、实例化测试套件
s = unittest.TestSuite()
# 向测试套件添加单个用例
s.addTest(Denglu("test_001"))
# 向测试套件添加多个用例
s.addTests([Denglu("test_001"),Testdemo("test_hello")])
运行后:
2.2、TestLoader加载用例
import unittest
s = unittest.TestLoader().discover(r"D:\lemonban\test")
print(type(s))
print(s)
运行后:
s = unittest.TestLoader().discover(目录)
从start_directory这个目录下开始,搜索所有的测试用例,并加载到测试套件当中。
1、指定搜索目录
2、文件过滤规则:以文件名匹配。test*.py
3、在文件当中过滤用例:继承了unittest.TestCase类的测试类,类当中以test_开头的测试函数。
3、执行用例+测试报告
3.1、TextTestRunner
import unittest
s = unittest.TestLoader().discover(r"D:\lemonban\test")
# 运行测试用例并生成结果
runner = unittest.TextTestRunner()
runner.run(s)
运行后:
3.2、HTMLTestRunner
HTMLTestRunnerNew.py放到python安装目录的lib目录下
import unittest
s = unittest.TestLoader().discover(r"D:\lemonban\test")
# 运行测试用例并生成结果
from HTMLTestRunnerNew import HTMLTestRunner
with open("my_report.html","wb") as file:
runner = HTMLTestRunner(file,title="21年度自动化测试报告",tester="鲁班")
runner.run(s)
运行后:
查看my_report.html报告:
可以点击详细查看:
如果有用例未通过时,会显示错误信息
3.3、BeautifulReport(安装:pip install BeautifulReport)
import unittest
from BeautifulReport import BeautifulReport
s = unittest.TestLoader().discover(r"D:\lemonban\test")
br = BeautifulReport(s)
br.report("21年度自动化测试报告","my_report.html")
运行后:
查看报告:
如果有用例未通过时,展开查看报错信息
4、前置后置fixture(放在用例文件)
- 1、setUp, tearDown --类下面的每个用例在执行之 前,会执行setup,在每一个用例执行之后,会执行teardown
setUp → 测试用例 → tearDown - 2、setUpCLass, tearDownClass - -类 里面的第一个用例执行之
前,执行setupCLass,类里面的最后一个用例执行之后,执行teardownCLas setupCLass → 测试类 → teardownCLass
用例:test_case_login.py
from loginlx import login_check
import unittest
class Denglu(unittest.TestCase):
def setUp(self):
print("单个用例开始执行......")
def tearDown(self):
print("单个用例执行结束......")
def test_001(self):
res = login_check("zhanghao","mima")
self.assertEqual(res,{"code": 0, "msg": "登录成功"})
def test_002(self):
res = login_check("zhanghao1","mima")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不正确"})
def test_003(self):
res = login_check("zhanghao","mima1")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不正确"})
def test_004(self):
res = login_check("mima")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不能为空"})
def test_005(self):
res = login_check("zhanghao")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不能为空"})
运行run.py:
import unittest
from test_case_login import Denglu
from test_case_demo import Testdemo
s = unittest.TestLoader().discover(r"D:\lemonban\test")
# 运行测试用例并生成结果
runner = unittest.TextTestRunner()
runner.run(s)
运行后:
test_case_login.py
class Denglu(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("Denglu类下面的用例开始执行......")
@classmethod
def tearDownClass(cls):
print("Denglu类下面的用例结束执行......")
def test_001(self):
res = login_check("zhanghao","mima")
self.assertEqual(res,{"code": 0, "msg": "登录成功"})
def test_002(self):
res = login_check("zhanghao1","mima")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不正确"})
def test_003(self):
res = login_check("zhanghao","mima1")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不正确"})
def test_004(self):
res = login_check("mima")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不能为空"})
def test_005(self):
res = login_check("zhanghao")
self.assertEqual(res,{"code": 1, "msg": "账号或密码不能为空"})
运行run.py:
import unittest
from test_case_login import Denglu
from test_case_demo import Testdemo
s = unittest.TestLoader().discover(r"D:\lemonban\test")
# 运行测试用例并生成结果
runner = unittest.TextTestRunner()
runner.run(s)
运行后:
5、用例执行顺序: ASCII码
ASCII码的大小规则: 0-9<A-Z<a-z
例如:文件名,test_login.py和test_test.py,就会先执行test_login.py模块然后进入到文件内部,按照此规则识别类名,再识别用例名称。
如果你想自己指定执行顺序,在文件名或者用例名称上做文章
6、ddt 数据驱动测试(一定要跟测试框架一起用)
ddt:全称data driven test
安装:pip install ddt
使用方法:
-
1、列表 = 准备好N组测试数据
-
2、import ddt
-
3、类名上面:@ddt.ddt
-
4、测试流程函数上面:@ddt.data(*列表)
-
5、在测试函数的参数中,定义一个参数用来接收每一组测试数据。
-
ddt是一种设计思维,一个测试流程,N组测试数据 ;流程不变,只是测试数据和断言的数据不一样。
例如前面的test_case_login.py,测试流程都是相同的,只有数据不一样
此时,使用ddt方法,修改用例文件 test_case_login.py
from loginlx import login_check
import unittest
from loginlx import login_check
import unittest
# 导入ddt
import ddt
# 创建一个列表嵌套字典
datas = [{"user":"zhanghao","passwd":"mima","expected":{"code": 0, "msg": "登录成功"}},
{"user":"zhanghao1","passwd":"mima","expected":{"code": 1, "msg": "账号或密码不正确"}},
{"user": "zhanghao", "passwd": "mima1", "expected": {"code": 1, "msg": "账号或密码不正确"}},
]
@ddt.ddt # 在类名上面,用@ddt.ddt
class Denglu(unittest.TestCase):
#在测试函数上面,用@ddt.data(*列表) #拆包后将多组测试数据依次传递给一个测试流程
@ddt.data(*datas)
def test_list(self,case):#在测试函数的参数中,定义一个case参数用来接收每一组测试数据
res = login_check(case["user"],case["passwd"])
self.assertEqual(res,case["expected"])
run.py运行后: