文章目录
一、接口自动化之Cookie, Session, Token
1、Cookie
-
什么是Cookie?
Cookie是在服务器产生的,存储在客户端的一小段文本信息,格式是字典(键值对) -
Cookie的分类
会话级:保存在内存,当浏览器关闭就会丢失
持久化:保存硬盘,只有当失效时间到了才会被清除 -
Cookie如何实现鉴权
当客户端第一次访问服务器,服务器就会产生cookie,然后通过响应头的方式在Set-Cookie里面传输到客户端。客户端从第2-N次请求,都会自动带上这些Cookie -
弱点:Cookie保存在客户端,对于一些敏感信息,用户名、密码等不安全
-
代码示例
import re
import unittest
import requests
'''
cookie 鉴权
'''
class CookieJiangquan(unittest.TestCase):
# token鉴权
csrf_token = ""
csrf_cookie = ""
def test_01_index(self):
url = "http://192.168.80.80/phpwind"
res = requests.get(url)
# 此时获取token,下面的接口方法需要
# 通过正则表达式获取
value = re.search('name="csrf_token" value="(.+?)"',res.text)
CookieJiangquan.csrf_cookie = value.group(1) # 第一个查询到的值
CookieJiangquan.csrf_cookie = res.cookies # cookie使会话连接
def test_02_login(self):
url = "http://192.168.80.80/phpwind/index.php?m=xx&x=jj"
data = {
"username":"admin",
"password":"pwd",
"csrf_token":CookieJiangquan.csrf_token
}
headers = {
"Accept":"application/json",
"X-Requestd-With":"XMLHttpRequest"
}
# 手动带上cookie信息进行请求
res = requests.post(url,data=data,headers=headers,cookie=CookieJiangquan.csrf_cookie)
2、Session
- 当用户一次访问服务器的时候,在服务器端保存一个sessionid,这个sessionid是经过加密的,然后通过cookie把这个sessionid保存到客户端,然后请求服务器的时候只发送sessionid。
- 代码示例
class CookieJiangquan(unittest.TestCase):
# 全局变量
session = requests.session()
# 直接使用session来进行请求,保持为一个对话
res = CookieJiangquan.session.get(url)
...
res = CookieJiangquan.session.post(url,data=data,headers=headers)
- 弱点:解决了cookie不安全的问题,但也产生了新的问题。当用户量特别大时,会导致服务器崩溃。
3、Token鉴权
- 当一个用户登录之后,就给他发送一个token令牌,下一次用户再次请求的时候,只需要带上这个令牌。token是可以通过抓包抓取的。
加密:
对称加密:DES,AES
双钥加密:RSA
只加密不解密:MD5,SHA - token的分类
access_token:有时间限制,一般在15分钟
refresh_token:一般15天
cookie,session,token的相同和区别
- 相同点:都是用于做鉴权的,都是服务器产生的
- 区别:
- cookie存储在客户端,session存储在服务器端,session的安全性比cookie高,一般情况下把重要的信息放在session,把不重要的放在cookie
- session是存在服务器的内存,token存在服务器的文件或者数据库中,token的好处是比session更省服务器的资源,token只需要在服务器解密即可
- 自动化层面:
工具:postman,jmeter
代码:接口关联,cookie鉴权,session鉴权,web自动化用cookie跳过验证码
二、自动化框架
1、自动化框架了解
- 什么是框架?
框架其实是开发定制研发的应用骨架,是一个半成品,它对基础的代码进行了封装并提供一些API接口。其他开发者只需要调用封装好的API接口即可,可以省去很多代码编写,从而提高工作效率 - 自动化框架以及它的作用
(1) 自动化测试框架
自动化测试leader为了对一个系统做自动化测试而封装的一个代码主骨架,其他自动化测试工程师只需要去调用这个骨架里面的方法就可以实施自动化测试,这个代码骨架就叫自动化框架。
(2) 自动化框架的作用
– 提高测试效率,降低维护成本
– 减少人工干预脚本因素
– 增加代码的可重用率
(3) unittest单元测试框架和自动化测试框架的关系
– 单元测试:针对我们程序的最小单元(方法)进行测试
– unittest是自动化框架的重要组成部分之一
(pom,ddt数据驱动,全局配置封装,selenium二次封装,日志监控,断言,邮件发送)
2、单元测试框架对比
基于python语言:unittest和ptest
基于java语言:junit和testing
- 用例编写规则
unittest
:提供了testcases测试用例、testsuites测试套件、testfixtures夹具、testloader测试加载器、testrunner测试运行器,必须遵守以下规则:
- 测试文件必须先导入 import unittest
- 测试类必须继承unittest.TestCase
- 测试方法必须以test开头
pytest
:它是python的第三方测试框架,基于unittest的扩展框架,必须遵守以下规则:
- 测试文件名必须以test_开头或者_test结尾
- 测试类命名必须以Test开头
- 测试方法必须以test开头
- 用例的前置和后置
- unittest:
setUp/testDown:在每个用例之前或者之后运行一次(打开浏览器,加载网页/关闭网页)
setUpClass/testDownClass:在每个类运行之前或者之后运行一次(创建数据库连接/创建日志对象/关闭数据库连接/销毁日志对象)
setUpModule/testDownModule:在每个模块之前或者之后运行一次 - pytest:
方法级:setup_method/teardown_method 在方法之前和之后
setup/teardown
函数级:
setup_function/teardown_function 在函数之前和之后
类级别:
setup_calss/teardown_class
模块级别:
setup_module/teardown_module
还有:可以在函数之前加@pytest.fixture()
-
断言
unittest:assertTrue,assertEqual,assertIn
pytest:assert -
报告
unittest:htmltestrunner
pytest:插件:pytest-HTML,allure -
失败重跑
unittest:没有
pytest:pytest-rerunfailures插件 -
数据驱动
unittest:ddt
pytest:@pytest.mark.parametrize装饰器 -
用例分类执行
unittest:默认执行所有,也可以通过testsuite来执行部分用例,或者-k参数
pytest:@pytest.mark
三、Unittest框架
- unittest框架主要做了什么
– 测试发现:从多个py文件中收集并加载测试用例
– 测试执行:将测试用例按照一定的顺序和条件去执行并且生成结果
– 测试判断:通过断言去判断结果是否正确
– 测试报告:统计测试进度,通过率,生成报告 - unittest重要组件
TestCase: 测试用例
TestSuite:测试套件
TestFixture:夹具
TestLoader:测试加载器
TestRunner:测试运行器
3.1 TestCase用法
import unittest
class EcshopLogin(unittest.TestCase):
# 测试用例
def test01_baili(self):
print("测试unittest")
- 使用unittest命令行的方式运行
python -m unittest -v ecshop_login.EcshopLogin.test01_baili
python -m 以脚本的方式运行一个模块
unittest -v 更详细的输出结果
ecshop_login.EcshopLogin.test01_baili:模块名.类名.方法名
-k 匹配模式:
通配符:-k *_weiwei
字符串:-k weiwei
- 集成 jenkins 的时候使用,所有的命令行方式都为非GUI方式
postman: 非GUI,newman
jmeter: jmeter命令
- 使用unittest.main(),以模块的方式运行
if __name__ == '__main__':
unittest.main()
配置pycharm的环境 或者 命令行运行:D:\PyCharm\Code\demo2>python ecshop_login.py
- 用例的执行结果:
. 成功
F 失败
E 错误
S 跳过
# 测试用例
@unittest.skip("此用例不执行") # s
def test01_baili(self):
raise Exception("自定义异常") # Error
self.assertTrue(0) # Failure
print("测试unittest")
def test02_weiwei(self): # 成功.
print("测试微微")
3.2 用例的执行顺序
按ASCII码的规则:【0-9 A-Z a-z】 A=65 a=97
import os
import unittest
class EcshopLogin(unittest.TestCase):
# 测试用例
# @unittest.skip("此用例不执行") # s
def test01_baili(self):
# raise Exception("自定义异常") # Error
# self.assertTrue(0) # Failure
print("测试unittest")
def test02_weiwei(self): # 成功.
print("测试微微")
def test03_xiexie(self):
print("测试谢谢")
if __name__ == '__main__':
...
- 使用套件可以指定执行 suite = unittest.TestSuite()
# 加载单个用例 suite.addTest
suite.addTest(EcshopLogin("test01_baili"))
# 加载多个用例 suite.addTests
testcases = [EcshopLogin("test01_baili"),EcshopLogin("test02_weiwei")]
suite.addTests(testcases)
# 找到所有用例
testcases = unittest.defaultTestLoader.discover(start_dir=os.getcwd(),pattern='*.py')
- 执行
# unittest.main(defaultTest='suite')
unittest.TextTestRunner().run(suite) # 与上面的执行方式是同样的
3.3 TestFixture测试夹具
- 将夹具进行二次封装,写在一个类之中,而写有测试用例的类,只需要去继承这个类,就可以拥有这些方法。
'''
很少用到:
def setUpModule():
print("模块级的夹具---开始")
def tearDownModule():
print("模块级的夹具—--结束")
'''
class MyUnit(unittest.TestCase):
@classmethod
def setUpClass(cls):
print("setUpClass:每个类之前执行一次,例如创建数据库,生成日志对象")
def setUp(self):
print("\nsetUp:测试用例前的准备工作,例如打开浏览器,加载网页")
def tearDown(self):
print("tearDown:测试用例之后的扫尾工作,例如关闭浏览器")
@classmethod
def tearDownClass(cls):
print("tearDownClass:每个类之后执行一次,例如关闭数据库链接,销毁日志对象")
from my_unit import MyUnit
# 继承
class Test2(MyUnit):
def test01_weiwei(self): # 成功.
print("测试2")
- 忽略测试用例 skip
可以作用在类上(较少),也可以作用在方法上(忽略一些不想执行的用例)
@unittest.skip("此模块暂不测试")
class EcshopLogin(MyUnit):
age = 22
# 测试用例
@unittest.skip("此用例不执行")
def test01_baili(self):
print("测试unittest")
@unittest.skipIf(age>=18 and age<=25,"如果满足条件就忽略")
def test02_weiwei(self):
print("测试微微")
@unittest.skipUnless(age<18,"如果不满足条件则忽略")
def test03_xiexie(self):
print("测试谢谢")
3.4 unittest单元框架中的断言
断言 | |
---|---|
assertEqual(a,b) | 断言 a==b |
assertNotEqual(a,b) | 断言 a!=b |
assertTrue(a) | 断言a为真 |
assertFalse(a) | 断言a为假 |
assertIn(a,b) | 断言a在b里 |
assertNotIn(a,b) | 断言a不在b里 |
3.5 批量执行用例生成HTML格式的报告
需要下载HTMLTestRunner.py文件
参考文章进行修改:HTMLTestRunner使用方法
- 官网下载的文件不支持python3.x
- 使用之前需要先进行导入 from HTMLTestRunner import HTMLTestRunner
import os
import unittest
from HTMLTestRunner import HTMLTestRunner
if __name__ == '__main__':
suite = unittest.TestSuite()
testcases = unittest.defaultTestLoader.discover(start_dir=os.getcwd(), pattern='*.py')
suite.addTests(testcases)
# unittest.TextTestRunner(verbosity=2).run(suite) # 详细输出verbosity=2,默认1
nowtime = time.strftime("%Y-%m-%d %H-%M-%S",time.localtime()) # 格式化时间
name = open(os.getcwd()+"/"+nowtime+"_report.html","wb")
runner = HTMLTestRunner(stream=name,verbosity=2,title="测试报告",description="报告详细如下:")
runner.run(suite)
- 运行示例:
def test01_paopao(self):
"""测试天天""" # 注解
print("测试1")
self.assertEqual(1,2) # 错误
四、Pytest框架
- pytest简介
- pytest是一个非常成熟的python的单元框架,比unittest更灵活,容易上手
- pytest可以和selenium,requests,appium结合实现web自动化,接口自动化,app自动化
- pytest可以实现测试用例的跳过以及reruns失败用例重试
- pytest可以和allure生成非常美观的测试报告
- pytest有很多非常强大的插件,并且这些插件可以实现很多实用的操作
pytest-html (生成html格式的自动化测试报告),
pytest-xdist (测试用例分布执行,多CPU分发),
pytest-ordering (用于改变测试用例的执行顺序),
pytest-retunfailures (用例失败后重跑),
allure-pytest (用于生成美观的测试报告)
- pytest插件下载
在项目的根目录下新建文件requirements.txt,在里面写需要的插件名称,然后通过命令一次性下载:pip install -r requirements.txt
4.1 使用pytest,默认的测试用例规则及基础应用
- 书写规则
- 块名必须以test_开头或者_test结尾
- 测试类必须以Test开头,并且不能有init方法
- 测试方法必须以test开头
- pytest测试用例的运行方式
- 主函数模式
(1)运行所有:pytest.main()
(2)指定模块:pytest.main(['-vs','test_login.py'])
(3)指定目录:pytest.main(['-vs','./new_testcase'])
(4)通过nodeid指定用例运行:nodeid是由模块名,分隔符,类名,方法,函数名组成
pytest.main(['-vs','./new_testcase/test_newtest.py::test_04_func'])
- 命令行模式
(1)运行所有:pytest
(2)指定模块:pytest -vs test_login.py
(3)指定目录:pytest -vs ./new_testcase
(3)指定nodeid:pytest -vs ./new_testcase/test_newtest.py::test_04_func
- 通过读取pytest.ini配置文件运行
- 主函数模式
- 参数详解:
-s:表示输出调试信息,包括print打印的信息
-v:显示更详细的信息
-n:支持多线程或者分布式运行测试用例(如:pytest -vs ‘./testcase’ -n 2)
–rerun NUM:失败用例重跑(pytest -vs ./testcase --reruns 2)
-x:表示只有有一个用例报错,那么测试停止
–maxfail=2:出现两个用例失败就停止
-k:根据测试用例的部分字符串指定测试用例(pytest -vs ./testcase -k “cc”)
–html ./report/report.html:生成html的测试报告
4.2 pytest执行测试用例的顺序
unittest:ascll码的大小来决定执行的顺序
pytest:默认从上到下
- 改变默认的执行顺序:使用mark标记
1. 通过读取 pytest.ini 配置文件运行
- pytest.ini 这个文件是pytest单元测试框架的核心配置文件(一般放在项目的根目录)
- 编码:文件编码必须是ANSI,可以使用notepad++修改编码格式
- 作用:改变pytest的默认行为
- 运行规则:不管是主函数还是命令行的模式运行,都会去读取这个配置文件
[pytest]
addopts = -vs # 命令行的参数,用空格分隔
testpaths = ./testcase # 测试用例的路径
python_files = test_*.py # 模块名的规则
python_classes = Test* # 类名的规则
python_functions = test_* # 方法名的规则
markers = # 可以自定义分组
smoke:冒烟用例
usermanage:用户管理
productmanage:商品管理
2. 如何分组执行(冒烟,分模块执行,分接口和web执行)
smoke:冒烟用例,分布在各个模块中
pytest -vs -m “smoke or usermanage”
@pytest.mark.smoke
def test_02_aa(self):
print("这是百丽2")
# assert 1==2
@pytest.mark.usermanage
def test_03_bb(self):
print("这是百丽3")
3. pytest跳过测试用例
- 无条件跳过
- 有条件跳过
4.3 pytest框架实现的一些前后置处理(固件、夹具)
1. setup/teardown,setup_class/teardown_class
注意:和unittest不一样,pytest全是小写
class TestMashang:
# 在所有用例之前只执行一次
def setup_class(self):
print("在每个类执行前的初始化工作:比如创建日志对象,创建数据库")
# 在每个用例之前执行一次
def setup(self):
print("在执行测试用例之前执行的代码: 打开浏览器,加载网页")
def test_05_meili(self):
print("测试美丽")
def teardown(self):
print("在执行测试用例之后执行的代码: 关闭浏览器")
def teardown_class(self):
print("在每个类之后执行的扫尾工作,比如销毁日志对象,销毁数据库的连接")
2. 使用@pytest.fixture()
装饰器来实现部分用例的前后置
@pytest.fixture(scope="",params="",autouse="",ids="",name="")
- scope:表示是被@pytest.fixture标记的方法的作用域,function(默认),class,module,package,session
- autouse:自动执行,默认False
import pytest
# 如果希望所有方法都实现前置,则加上参数 autouse=True
@pytest.fixture(scope="function")
def my_fixture():
print("这是前置的方法,可以实现部分以及全部用例的前后置")
yield
print("使用yield实现后置")
class TestMashang():
def test_05_meili(self):
print("测试美丽")
# 作为参数进行调用,实现前后置
def test_06_biaoji(self,my_fixture):
print("测试标记")
- params:参数化(支持list[],tuple(),字典列表[{},{}],字典元组({},{}))
注意:params是参数名,有s;request.param是属性名,没有s
@pytest.fixture(scope="function",params=['baby','xiao','shishi'])
def my_fixture(request):
# 使用request接收参数,使用request.param返回(固定写法)
# return request.param
yield request.param # return和yield都表示返回的意思,但是return后面不能有代码,而yield返回后面可以接代码
# 可以写后置代码
# 有三个参数,该用例会执行三次
def test_06_biaoji(self,my_fixture):
print("测试标记")
print('------------'+str(my_fixture))
- ids:当使用params参数化时,给每一个值设置一个变量名,意义不大
- name:给被@pytest.fixture标记的方法取一个别名
当取了别名之后,原来的名称就用不了了
@pytest.fixture(scope="function",params=['成龙','萧','诗诗'],ids=['cl','xiao','shi'],name='aaaa')
# 设置别名之后,引用也需要改为别名,否则会报错
def test_06_biaoji(self,aaaa):
print("测试标记")
print('------------'+str(aaaa))
3. 通过conftest.py
和@pytest.fixture()结合使用实现全局的前置应用
- conftest.py文件是单独存放的一个夹具配置文件,名称不能更改
- 用处:可以在不同的py文件中使用同一个fixture函数
- conftest.py需要和运行的用例放在同一层,并且不需要做任何import导入操作
总结:
setup/teardown,setup_class/teardown_class 它是作用于所有用例或者所有的类
@pytest.fixture() 它的作用是既可以部分也可以全部前后置
conftest.py和@pytest.fixture() 结合使用,作用于全局的前后置
4.4 断言
assert 1==2
4.5 pytest 结合 allure-pytest 插件生成 allure 测试报告
- 之前使用过pytest-html生成报告,但比较简单不美观
addopts = -vs --html ./report/report.html
2. allure的配置与安装
- 下载,解压,配置path路径
https://github.com/allure-framework/allure2/releases
验证:allure --version
- 生成json格式的临时报告
addopts = -vs --alluredir ./temp
- 生成allure报告
if __name__ == '__main__':
pytest.main()
# allure generate固定语法 ./temp找到临时报告 -o 输出 到当前的 ./report目录下 --clean清空原有的报告
os.system('allure generate ./temp -o ./report --clean')