定义:
unittest是python自带的单元测试框架,也是python中最基本的单元测试框架,存放在python安装目录的lib目录下
为什么要使用unittest框架?
在项目内使用unittest框架来组织和规范测试用例
unittest中最核心的四个概念
1.test case:测试用例
2.test fixture:测试夹具
3.test runner:测试执行
4.test suite:测试套件
1.测试用例
1.1unittest的书写规则
1.1.1 测试文件必须以test开头,如:test_01_unittest入门脚本.py
1.1.2 测试类必须继承unittest.TestCase类
1.1.3 测试类必须以Test开头,如:class TestLogin(unittest.TestCase):
1.1.4 测试方法最好以test开头,如:def test_01_login(self):
1.1.5 在测试的py文件中执行代码,使用unittest.main()
1.1.6 在测试类里面可以有普通方法,但普通方法必须要有测试方法调用
综合代码如下:
import unittest
class TestLogin(unittest.TestCase):
def test_login(self):
print("正常的用户登录")
def test_login_remember(self):
print("记住用户信息登录")
if __name__ == '__main__':
unittest.main()
1.2 用例的执行顺序
在unittest中用例的执行顺序默认按照ASCII码的顺序
想要自定义测试用例的执行顺序,需要给每条用例加上执行序号
import unittest
class TestLoginPay(unittest.TestCase):
def test_01_login(self):
print("用户进行登录")
def test_02_view_page(self):
print('用户浏览商品')
if __name__ == '__main__':
unittest.main()
1.3 断言
断言:断言是指判断预期结果与实际结果是否相符合
语法:
1.3.1 判断预期结果与与实际结果是否相等
self.assertEqual(a,b,msg="错误描述")
1.3.2 判断用例表达式结果是否为True,为True则通过
self.asserTrue(表达式,msg="错误描述")
1.3.3 判断预期结果是否在实际结果中,适用于实际结果内容较长,在实际结果中则通过
self.assertIn(a,b,msg="错误描述")
下图为综合举例
import unittest
class TestLogin(unittest.TestCase):
def test_01_login(self):
excepted = "admin"
result = "admin"
self.assertEqual(excepted, result, "用户名错误")
print("用户登录")
def test_02_open_goods(self):
excepted = "打开商品页面1"
result = "打开商品页面"
self.assertTrue(excepted == result, "网络波动,打开商品页面失败")
print("打开商品页面")
def test_03_pay_for_goods(self):
excepted = "花钱"
result = "给商品花钱"
self.assertIn(excepted, result, "不愿意花钱")
print("给商品花钱")
if __name__ == '__main__':
unittest.main()
1.4 跳过测试
什么时候使用?
当我们写的部分用例在某些情况下无需执行时,可以跳过
当系统更新后,部分测试用例失效,但不确定是否会再次使用时,可以跳过
语法(使用装饰器实现跳过):
@unittest.skip(原因) 直接跳过,无限制条件
@unittest.skipif(表达式,原因) 表达式为True时,跳过
@unittest.skipunless(表达式,原因) 表达式为False时,跳过
下图为综合举例(random,随机数模块)
import unittest
import random
num = random.randint(0, 1)
class TestLoginPay(unittest.TestCase):
@unittest.skip("无法打开网页")
def test_02_view_page(self):
print('用户浏览商品')
@unittest.skipIf(1 == 1, "客户无中意商品")
def test_04_add_cart(self):
print('用户加购中意商品')
@unittest.skipUnless(num == 1, "没钱跳过支付")
def test_06_pay_for_order(self):
print('用户支付商品订单')
if __name__ == '__main__':
unittest.main()
2.test fixture 测试夹具
定义:
测试夹具作用在类或方法之前和之后,将测试代码夹起来
语法:
1.方法级别的测试夹具
setup() 每个测试方法执行之前执行
teardown() 每个测试方法执行之后执行
2.类级别的测试夹具(需要用@classmethod装饰起来)
setupclass() 类执行之前执行(可以写打开网页的代码)
teardownclass() 类执行之后执行(可以写关闭网页的代码)
下图为综合举例
import unittest
class TestLogin(unittest.TestCase):
def test_login(self):
print("正常的用户登录")
def test_login_remember(self):
print("记住用户信息登录")
def setUp(self) -> None:
print("setup在每个测试方法执行之前执行")
def tearDown(self) -> None:
print("teardown在每个测试方法执行之后执行")
@classmethod
def setUpClass(cls) -> None:
print("setupclass在每个测试类执行之前执行")
@classmethod
def tearDownClass(cls) -> None:
print("teardownclass在每个测试类执行之后执行")
if __name__ == '__main__':
unittest.main()
3.测试套件和测试执行
test suite 测试套件:将需要执行的测试用例放到一个套子里
test runner 测试执行:执行测试套件中的测试用例
3.1 执行所在文件中所有的用例 unittest.main()
import unittest
class TestLogin(unittest.TestCase):
def test_login(self):
print("正常的用户登录")
if __name__ == '__main__':
unittest.main()
3.2 添加不同的测试用例(适用于调试某个测试用例)
前置条件:导包
import unittest
from Case.test_03_用例执行顺序 import TestLoginPay
from Case.test_04_断言 import TestLogin
3.2.1 实例化一个测试套件
suite = unittest.TestSuite()
3.2.2 添加想要执行的测试用例进测试套件
suite.addTest(TestLoginPay('test_01_login'))
suite.addTest(TestLoginPay('test_02_view_page'))
suite.addTest(TestLogin('test_02_open_goods'))
3.2.3 实例化一个测试执行对象
runner = unittest.TextTestRunner()
3.2.4 执行测试套件中的测试用例
runner.run(suite)
注意:执行结果: .代表通过;F代表False;T代表True;S代表跳过的用例
3.3 执行某目录下的所有的测试用例
默认执行目录下的所有测试用例
suite = unittest.defaultTestLoader.discover(需执行目录, pattern=执行规则)
执行规则默认"test*.py"
import unittest
suite = unittest.defaultTestLoader.discover("./Case", pattern='test_03*.py')
# 实例化测试执行对象
runner = unittest.TextTestRunner()
# 执行套件中的所有用例
runner.run(suite)
4.HTML测试用例报告生成
HTMLTestRunner:第三方插件,下载后放到python的安装目录下的lib文件
注意:
1.生成的报告放在Report文件里
2.生成的报告名应该以.html文件结尾
下面的代码为整体执行代码
# 导包
import unittest
import HTMLTestRunnerPlugins
import time
import os
# 拼接报告文件存放的位置,存放到Report目录下
report_path = os.path.dirname(__file__) + '/Report/'
print(report_path)
# 格式化输出当前的时间
now = time.strftime("%Y-%m-%d %H_%M_%S")
# 拼接报告文件的绝对路径,防止重名文件覆盖,加上时间戳确保文件名不一致
report_name = report_path + now + "HTMLReport.html"
# 获取Case目录下所有的用例装进一个suite套件中
suite = unittest.defaultTestLoader.discover("./Case")
# 以二进制文件写入的方式打开.html文件,并写入信息
with open(report_name, "wb") as fq:
# 实例化一个html执行用例获取报告的对象
runner = HTMLTestRunnerPlugins.HTMLTestRunner(
stream=fq, title="web自动化测试", # 报告标题
description="执行所有的测试用例", # 测试内容描述信息
tester="真的会谢") # 测试执行人
runner.run(suite) # 执行套件中的所有用例
5.数据驱动
安装ddt模块 使用pip install ddt 在命令行提示栏安装
数据驱动:有的用例只是参数不一样,其他的代码完全一致时就可以通过改变测试参数来实现一条用例方法执行多种不同的测试场景,在unittest里面要使用ddt来提供参数化的功能
ddt可以参数化读取列表嵌套列表或列表嵌套字典的数据
5.1 列表嵌套列表
import unittest
import ddt
from Common.OperationData import OperationData
from Page.LoginPage import LoginPage
data_list = OperationData('user_data.xls').get_data_list()
@ddt.ddt
class TestLoginDDt(unittest.TestCase):
@unittest.skip("暂不执行")
@ddt.data(*data_list)
@ddt.unpack
def test_login(self, username, password):
login = LoginPage("chrome")
login.open_login_url()
login.send_user_name(username)
login.send_password(password)
5.2 列表嵌套字典
import unittest
import ddt
from Common.OperationData import OperationData
from Page.LoginPage import LoginPage
data_dict = OperationData('user_data.xls').get_data_dict()
@ddt.data(*data_dict)
def test_login_dict(self, dict_data):
login = LoginPage("chrome")
login.open_login_url()
# 输入账号
login.send_user_name(dict_data['username'])
# 输入密码
login.send_password(dict_data['password'])
# 点击登录
login.click_login()
# 进行断言
if str(dict_data["expected"]) == '1':
self.assertTrue(login.login_after_assert(), msg="登录失败")
elif str(dict_data["expected"]) == '0':
self.assertTrue(not login.login_after_assert(), msg="登录失败")
else:
print("预期结果超过限制")
if __name__ == '__main__':
unittest.main()