UnitTest框架应用
为什么使用unittest框架?
1,能够组织多个用例去执行
2.提供丰富的断言方法
3,能够生成测试报告
UnitTest核心要素:
1.TestCase :测试用例
2.TestSuite : 测试套件
3.TestRunner : 以文本的形式运行测试用例
4.TestLoader :执行测试用例,批量执行–>搜索指定文件夹内指定字母开头的模块(推荐)
5.Fixture :固定装置 (两个固定的函数,一个初始化使用,一个结束时使用)
1.UnitTest框架基本使用
TestCase
案例:实现一个加法操作的函数,并对这个函数进行测试
步骤:
1.导包:import unittest
2.定义测试类:新建测试类必须继承unittest.TestCase
3.定义测试方法:测试方法名称必须以test开头
执行测试用例:
方法1.使用pycharm在代码上点击鼠标右键,选择使用UnitTest运行
方法2.调用unittest.main()来运行
#导包
import unittest
#求和函数
def add(a,b):
return a+b
#定义测试类
class Test01(unittest.TestCase):
# 定义测试方法
def test_add(self):
sum=add(1,1)
print('和为:',sum)
def test_add02(self):
sum = add(1, 2)
print('和为:', sum)
if __name__=='__main__':
unittest.main()
"""
__name__:为python中内置变量
值:
1.如果当前运行的模块为当前模块,那么__name__的值为:__name__
2.如果当前运行的模块不是主模块,那么__name__的值为:模块名称
"""
TestSuite
说明:测试套件:多条测试用例集合在一起,就是一个TestSuite
使用:
1.实例化:suite=unittest.testSuite()
(suite:为TestSuite实例化的名称)
2.添加用例:suite.addTest(ClassName(“MethodName”))
(classname:为类名,MethodName:方法名)
3.添加扩展:suite.addTest(unittest.makeSuite(ClassName))
(搜索指定ClassName内test开头的方法并添加到测试套件中)
TextTestRunner
说明:TextTestRunner是用来执行测试用例和测试套件的
使用:
1.实例化:runner=unittest.TextTestRunner()
2.执行:runner.run(suite) #suite:为测试套件名称
提示:TestSuite需要配合TestRunner才能执行
#导包
import unittest
#定义测试类
class Test02(unittest.TestCase):
def test001(self):
print('test001被执行')
def test002(self):
print('test002被执行')
def test003(self):
print('test003被执行')
if __name__=='__main__':
unittest.main()
"""
__name__:为python中内置变量
值:
1.如果当前运行的模块为当前模块,那么__name__的值为:__name__
2.如果当前运行的模块不是主模块,那么__name__的值为:模块名称
"""
#导包
import unittest
#求和函数
def add(a,b):
return a+b
#定义测试类
class Test01(unittest.TestCase):
# 定义测试方法
def test_add(self):
sum=add(1,1)
print('和为:',sum)
def test_add02(self):
sum = add(1, 2)
print('和为:', sum)
if __name__=='__main__':
unittest.main()
"""
目标:unittest框架:testSuilte的使用 textTestRunner使用
操作:1.导包
2.实例化,获取Suite对象
3.调用addTest方法,添加用例到指定的套件中
"""
import unittest
from day04.unittest01 import Test01
#实例化
suite=unittest.TestSuite()
#调用添加方法(写法1:类名('方法名')) 注意:方法名称使用双引号
suite.addTest(Test01("test_add"))
suite.addTest(Test01("test_add02"))
#执行测试操作
runner=unittest.TextTestRunner()
runner.run(suite)
"""
目标:unittest框架:testSuilte的使用
操作:1.导包
2.实例化,获取Suite对象
3.调用addTest方法,添加用例到指定的套件中
"""
import unittest
from day04.unittest01 import Test01
from day04.test02 import Test02
#实例化
suite=unittest.TestSuite()
# #调用添加方法(写法1:类名('方法名')) 注意:方法名称使用双引号
# suite.addTest(Test01("test_add"))
# suite.addTest(Test01("test_add02"))
#扩展 添加测试类中所有test开头的方法
'''
'''
suite.addTests(unittest.makeSuite(Test02))
#执行测试套件
runner=unittest.TextTestRunner()
runner.run(suite)
TestLoader
说明:
用来加载TestCase到TestSuite中,即加载满足条件的测试用例,并把测试用例封装成测试套件
使用unittest.testLoader,通过该类下面的discover()方法自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件:
用法:
suite=unittest.TestLoader().discover(test_str,pattern=“test.py”)
自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件
test_str :为指定的测试用例的目录
pattern :为查找的.py文件的格式。默认为test.py
运行:
'''
目标:TestLoader()类的用法
作用:搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件,最后返回测试套件
需求:运行case目录下test01-test05.py文件
操作:
1.导包 unittest
2.调用testLoader类下的discover方法
'''
import unittest
#调用testLoader类下的discover方法
suite=unittest.TestLoader().discover("../case")
#执行 套件 方法 TextTestRunner
unittest.TextTestRunner().run(suite)
扩展1:
import unittest
#调用testLoader类下的discover方法
#suite=unittest.TestLoader().discover("../case")
#扩展:使用tpshop开头的模块
suite=unittest.TestLoader().discover("../case",pattern="tpshop*.py")
#执行 套件 方法 TextTestRunner
unittest.TextTestRunner().run(suite)
扩展2:
import unittest
#扩展:使用defaultTestLoader
suite=unittest.defaultTestLoader.discover("../case")
#执行 套件 方法 TextTestRunner
unittest.TextTestRunner().run(suite)
2.Fixture
为了解决在一个测试类中定义多个测试方法,查看每个测试方法执行玩所花费的时长
说明:Fixture是一个概述,对一个测试用例环境的初始化和销毁就是一个Fixture
Fixture控制级别:
1.方法级别
2.类级别
3.模块级别
2.1方法级别
2.2类级别
2.3模块级别
3.断言
4.Html测试报告
测试用例的管理一般基于UnitTest、PyTest来进行管理,会更好的高效简洁
UnitTest:目前应用占据大半壁江山的一套测试框架。最初做单元测试,随着自动化测试的发展,到现在成为自动化测试技术的主流应用,尤其是接口自动化。
因为UnitTest中封装有非常多的内容,且可以和其他模块进行完美cp组合,所以在用例管理上和代码管理上会有更大的便利
四大特色:
-
测试用例的管理
-
测试套件和运行器,能够更有效的针对业务来运行用例管理,包括测试报告的集成
-
SetUp和Teardown,前置与后置条件
-
断言机制,只需要通过self.就可以直接调用
环境部署 -
UnitTest是一个测试用例框架
-
Python安装时默认会有一个builtin模块,UnitTest框架是默认集成在Python中的,意味着只要安装Python就有UnitTest
-
只需要通过import unittes即可实现调用
'''
UnitTest测试框架应用
1.类名继承unittest.TestCase
2.测试用例:所有的测试用例都是以函数的形式存在,函数的名称必须以test开头或者结尾
3.通过unittest.main()来执行测试用例
4.用例加载顺序:UnitTest中有默认的加载顺序:0-9,a-z,A-Z
5.所有的前置后置都有等级存在:class级别,method级别
class级别前置后置:必须定义装饰器@classmethod
前置是在所有用例运行前执行一次
后置是所有内容运行结束后执行一次
method级别前置后置:所有的前置与后置有且只有一个
method级别前置后置:与用例关联,每一条用例运行前会执行前置,运行后会执行后置
'''
#导入UnitTest模块
import unittest
# 如何真正意义上应用UnitTest框架:必须在类名继承unittest.TestCase
class UnitDemo(unittest.TestCase):
#须定义装饰器
#class级别:比如说,所有的配置
@classmethod
def setUpClass(cls)->None:
print('class前置条件');
# class级别
@classmethod
def tearDownClass(cls)->None:
print('class后置条件');
# 前置条件。 method级别:有且只有一个
def setUp(self)->None:#none意思是无返回值
print('前置条件');
#pass
# 后置条件:method级别:有且只有一个
def tearDown(self)->None:
print('后置条件');
#pass
# 测试用例:所有的测试用例都是以函数的形式存在,函数的名称必须以test开头或者结尾
# 测试用例的函数可以调用普通函数
def test_login(self):
print('这是测试用例login')
self.login();
def test_delete(self):
print('这是测试用例delete')
# 这是一个普通函数:封装逻辑代码,以便于在测试用例中进行调用
def login(self):
print('这是一个login函数');
# 要运行测试用例
if __name__ == '__main__':
# UnitTest执行测试用例
unittest.main()
UnitTest特有的日志信息:先执行delete,后执行login是因为UnitTest中有默认的加载顺序:0-9,A-Z,a-z(ASCII码决定的)(先排序,再执行)
UnitTest断言
让程序代替人为判断测试程序执行结果是否符合预期结果的过程
为什么要学习断言?
自动化脚本在执行的时候一都是在无人值守状态,我们不知道执行结果是否符合预期结果,所以我们需要让程序代替人为检测程序执行的结果是否符合预期结果,这就需要使用断言
方法
| assertTrue(exp,msg=None) | 验证expr是true,如果为false,则fail |
| assertFalse(expr,msg=None) |验证expr是false,如果为true,则fail |
| assertEqual(expected,actual,msg=None) | 验证expected==actual,不等则fail【掌握】|
| assertNotEqual(first,second,msg=None) | 验证first!=second,相等则fail|
| assertIsNone(obj,msg=None) | 验证obj是None,不是则fail|
| assertIsNotNone(obj,msg=None) | 验证obj不是None,是则fail|
| assertIn(member,container,msg=None) | 验证是否member in containner【掌握】|
| assertNotIn(member,container,msg=None) | 验证是否member not in containner|
#导包
import unittest
'''
目标:unittest框架常用断言
| assertTrue(exp,msg=None) | 验证expr是true,如果为false,则fail |
| assertFalse(expr,msg=None) |验证expr是false,如果为true,则fail |
| assertEqual(expected,actual,msg=None) | 验证expected==actual,不等则fail【掌握】|
| assertNotEqual(first,second,msg=None) | 验证first!=second,相等则fail|
| assertIsNone(obj,msg=None) | 验证obj是None,不是则fail|
| assertIsNotNone(obj,msg=None) | 验证obj不是None,是则fail|
| assertIn(member,container,msg=None) | 验证是否member in containner【掌握】|
| assertNotIn(member,container,msg=None) | 验证是否member not in containner|
'''
#定义测试类
class Test04(unittest.TestCase):
def test001(self):
# 1.断言是否为true
#flag = True
# flag=False
#
# self.assertTrue(flag)
#2.断言是否为flase
#flag = True
# flag=False
#
#self.assertFalse(flag)
#3.判断两个字符串是否相等
#self.assertEqual('hello','hello world')
#self.assertEqual('hello', 'hello')
# 4.判断两个字符串是否相等
#self.assertNotEqual('hello','hello world')
# self.assertNotEqual('hello', 'hello')
#7/8.判断后面的字符换是否包含前面字符串
#self.assertIn('hello','hello world')
# self.assertIn('1','hello world')
#self.assertNotIn('hello','hello world')
#self.assertNotIn('q', 'hello world')
#5/6.判断是否为空:None
#flag=None
#self.assertIsNotNone(flag)
#self.assertIsNone(flag)
断言练习
https://pan.baidu.com/
使用Unittest框架对某项目进行测试 https://pan.baidu.com(百度网盘)
进入登陆页面
输入用户名,不输入密码,直接点击登陆按钮
获取错误提示信息
断言错误提示信息是否为“请您输入密码”,如果断言失败则保存截图
'''
断言练习
https://pan.baidu.com/
使用Unittest框架对某项目进行测试 https://pan.baidu.com(百度网盘)
进入登陆页面
输入用户名,不输入密码,直接点击登陆按钮
获取错误提示信息
断言错误提示信息是否为“请您输入密码”,如果断言失败则保存截图
'''
#导包
import unittest
from time import sleep
from selenium import webdriver
#定义测试类 继承unittest.TestCase
class Test05(unittest.TestCase):
#定义初始化方法
def setUp(self):
#获取驱动对象
self.driver=webdriver.Chrome()
#打开浏览器
self.driver.get("https://pan.baidu.com")
#最大化浏览器
self.driver.maximize_window()
#隐式等待
#self.driver.implicitly_wait()
pass
#定义tearDown
def tearDown(self):
#关闭浏览器
sleep(5)
self.driver.quit()
pass
#定义测试方法 密码为空
def test_password(self):
#输入密码self.driver
driver=self.driver
driver.find_element_by_css_selector("#userName").send_keys("18691072207")
driver.find_element_by_css_selector("#password").send_keys("")
#点击登陆
driver.find_element_by_id("TANGRAM__PSP_4__submit").click()
#获取登陆后实际信息
result = driver.find_element_by_id("TANGRAM__PSP_4__error").text
print("result: ",result)
#定义预期结果
expect_result="请您输入密码"
try:
#断言
self.assertEqual(result,expect_result)
#截图
print("截图")
except AssertionError:
#截图
driver.get_screenshot_as_file("../image/error.png")
#抛异常
raise
扩展:python中的断言
'''
断言扩展:
两种实现方式:
1.unittest框架中的断言
2,python自带断言
'''
#python自带断言
#相等
#assert "hello" == "hel1o"
assert "hello" == "hell1o""不相等"
#第二个字符串是否包含第一个字符串
#assert "h" in "hello"
#assert "h6" in "hello"
#判断是否为true
#assert True
#判断是否为flase
#0 false 1 true
# assert 0
# assert 1
参数化
why?
解决冗余代码问题
what?
根据动态需求获取参数的过程并引用的过程
应用场景
解决相同业务逻辑,不同测试数据的问题
安装parameterized插件
parameterized 插件的应用
步骤:
导包 from parameterized import parameterized
修饰测试函数:@parameterized.expand(列表类型数据)
import unittest
from parameterized import parameterized
'''
需求:
目标:parameterized插件应用
步骤:
导包 from parameterized import parameterized
修饰测试函数:@parameterized.expand(列表类型数据)
测试函数中使用变量接受传递过来的值
语法:
单个参数:值为列表
多个参数:值为列表嵌套元组 如:[(1,2,3),(4,5,6)]
'''
class Test01(unittest.TestCase):
#单个参数使用方法
# @parameterized.expand("1","2","3")
# def test_add(self,num):
# print(num)
#多个参数使用方法 写法1
# @parameterized.expand([(1,2,3),(4,5,9)])
# def test_add(self, a,b,sum):
# print("{}+{}={}".format(a,b,sum))
#多个参数使用方法 写法2
# data=[(1,2,3),(4,5,9)]
# @parameterized.expand(data)
# def test_add(self, a,b,sum):
# print("{}+{}={}".format(a,b,sum))
#多个参数使用方法 写法3
def get_data():
return [(1,2,3),(4,5,9)]
@parameterized.expand(get_data())
def test_add(self, a,b,sum):
print("{}+{}={}".format(a,b,sum))
import unittest
from parameterized import parameterized
'''
问题:假如有三组数据需要测试
'''
def add(a,b):
return a+b
def get_data():
return [(1,1,2),(2,2,4),(3,3,9)]
class Test01(unittest.TestCase):
# 定义测试方法
@parameterized.expand(get_data())
def test_add(self,a,b,sum):
result=add(a,b)
#assert result==sum\
#assert result==sum
跳过
对于一些未完成的或不满足测试条件的测试函数和测试类,可以跳过执行
使用方式:
#直接将测试函数标记为跳过
@unittest.skip(‘代码未完成’)
#根据条件判断测试函数是否跳过
@unittest.skipIf(condition,reason)
"""\
跳过:
语法:@unittest.skipif(条件,原因)
@unittest.skip("原因")
"""
import unittest
verson=30
#新建测试类 1
#@unittest.skip("Test09方法功能暂未实现")
@unittest.skipIf(verson>25,"版本失效")
class Test09(unittest.TestCase):
#新建测试方法 1
#@unittest.skip("test01方法功能暂未实现")
def test01(self):
print("test01")
print()#此方法功能暂未完成
pass
#新建测试方法2
#@unittest.skipIf(verson>25,"版本失效")
def test02(self):
print("test02")