api.keys
api_keys.py
'''
接口的关键字驱动类底层:
1. 核心还是基于requests来实现的。
2. 整体还是以模拟请求为主
3. 响应的获取与解析
接口关联解决手段只有两种:
1. 将关联数据写入文件之中:适合相对于业务复杂程度更高的接口测试。
2. 将关联数据作为全局变量:适合关联数据相对较少的接口测试。
'''
import json
import jsonpath
import requests
from class35_interface_pytest.conf import set_conf
class Api:
def __init__(self, env):
self.env = env
# get请求:需要在方法中将常见的参数定义好
def do_get(self, path=None, params=None, headers=None, **kwargs):
# 获取url
url = self.set_url(path)
# 获取headers
headers = self.set_headers(headers)
return requests.get(url=url, headers=headers, params=params, **kwargs)
# post请求
def do_post(self, path=None, data=None, headers=None, json=1, **kwargs):
# 获取url
url = self.set_url(path)
# 获取headers
headers = self.set_headers(headers)
# print(headers)
# 发送post请求
if json == 1:
response = requests.post(url=url, headers=headers, json=data, **kwargs)
else:
response = requests.post(url=url, headers=headers, data=data, **kwargs)
return response
# 拼接URL
def set_url(self, path):
url = set_conf.read_conf('SERVERS', self.env)
if path:
url = url + path
return url
# 拼接headers
def set_headers(self, headers):
base_headers = {
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
"Chrome/115.0.0.0 Safari/537.36"
}
if headers:
# 如果用户传入新的headers值,则拼接在原有的base_headers之后
base_headers.update(headers)
if set_conf.read_conf('HEADERS', 'access-token'):
access_token = set_conf.read_conf('HEADERS', 'access-token')
base_headers['access-token'] = access_token
return base_headers
# 获取文本信息
def get_text(self, text, key):
text = json.loads(text)
values = jsonpath.jsonpath(text, key)
if values:
if len(values) == 1:
return values[0]
return values
# 断言校验
def assert_text(self, expected, text, key):
reality = self.get_text(text, key)
assert expected == reality, f'''
预期结果:{expected}
实际结果:{reality}
断言结果:{expected} != {reality}
'''
conf
conf.ini
[SERVERS]
devs = http://www.baidu.com/
tests = http://apihcc.fecmall.com/
online = http://www.jd.com/
[HEADERS]
access-token =
read_yaml.py
'''
读取yaml文件中的数据内容,作为测试数据的导入
'''
import yaml
# yaml文件中的内容获取
def read(path):
with open(path, 'r', encoding='utf-8') as file:
values = yaml.load(stream=file, Loader=yaml.FullLoader)
return values
# print(read('../test_data/login.yaml'))
set_conf.py
'''
配置和读取配置文件的内容,方便自动化测试的正常执行
'''
import configparser
import pathlib
# 获取配置文件
file = pathlib.Path(__file__).parents[0].resolve() / 'conf.ini'
# 配置项的读取
def read_conf(section, option):
conf = configparser.ConfigParser()
conf.read(file)
values = conf.get(section, option)
return values
# 配置项的写入
def write_conf(section, option, value):
conf = configparser.ConfigParser()
conf.read(file)
# 将指定的内容写入到conf之中
conf.set(section, option, value)
# 将写入操作进行保存
with open(file, 'w') as f:
conf.write(f)
# 配置项内容的清空
def clear_conf():
pass
demo
demo.py
'''
数据加密:
1. MD5加密
'''
import base64
import hashlib
# 进行md5加密
# md5 = hashlib.md5()
# pwd = 'hcc123456' # 需要加密的数据
# md5.update(pwd.encode('utf-8')) # 对数据进行加密操作
# print(md5.hexdigest()) # 输出加密后的数据
# md5加密封装
def md5(value):
md = hashlib.md5()
md.update(value.encode('utf-8'))
return md.hexdigest()
# print('准备测试数据')
# print('接口的密码数据加密执行')
# pwd = md5('hcchcchcc')
# print('数据加密后的结果:' + pwd)
# print('下发请求,传递加密后的数据包至对应请求')
# base64转码
url = 'hcc is 最棒的'
url = url.encode('utf-8')
print(url)
# 基本的base64转码
# a = base64.b16encode(url)
# # 转码后的数据
# print(a)
# print(str(a)[2:-1])
# b = base64.b32encode(url)
# print(b)
c = base64.urlsafe_b64encode(url)
print(c)
d = base64.urlsafe_b64decode(c)
print(d.decode('utf-8'))
test_cases
conftest.py
'''
conftest用于定义常用的Fixture:
如果conftest不生效,则将该文件直接放到test_cases路径下即可。
pytest测试用例管理的核心点在于conftest中,可以极大节省我们的维护时间成本
'''
import pytest
from class35_interface_pytest.api_keys.api_keys import Api
from class35_interface_pytest.conf import set_conf
# 生成api对象
@pytest.fixture(scope='session')
def api():
return Api('tests')
@pytest.fixture(scope='session')
def devs_api():
return Api('devs')
@pytest.fixture(scope='session')
def tests_api():
return Api('tests')
@pytest.fixture(scope='session')
def online_api():
return Api('online')
# 清空测试过程中生成的脏数据
@pytest.fixture(scope='session')
def clear(request):
def clear_finalizer():
set_conf.write_conf('HEADERS', 'access-token', '')
request.addfinalizer(clear_finalizer)
test_fecmall.py
'''
fecmall的基于pytest实现的测试用例管理:
1. 设置conftest.py
2. 测试用例的流程设计
3. allure测试报告的相关内容,包含常见的装饰器的调用
fecmall业务是:登录——获取多语言list——获取货币list
'''
import os
import allure
import pytest
from class35_interface_pytest.conf import set_conf
from class35_interface_pytest.conf.read_yaml import read
# 登录测试用例的设计
@allure.epic('实现fecmall从登录到获取语言与货币list的流程')
@allure.feature('基于access-token的数据获取')
@allure.story('实现fecmall登录流程')
@allure.title('用户登录,获取access-token')
@allure.step('登录操作步骤')
@pytest.mark.parametrize('data', read('../test_data/login.yaml'))
def test_login(api, data):
with allure.step('请求登录接口,获取响应结果'):
res = api.do_post(**data['request_data'])
print(res.text)
with allure.step('断言校验登录是否成功'):
api.assert_text(data['expected'], res.text, 'status')
with allure.step('将access-token数据添加到conf.ini文件之中'):
set_conf.write_conf('HEADERS', 'access-token', api.get_text(res.text, 'access-token'))
# 获取多语言list
@allure.epic('实现fecmall从登录到获取语言与货币list的流程')
@allure.feature('基于access-token的数据获取')
@allure.story('实现fecmall获取多语言list')
@allure.title('获取多语言list')
@allure.step('调用多语言接口')
def test_languages(api):
with allure.step('请求获取多语言list操作'):
res = api.do_get(path='/v1/languages')
with allure.step('展示响应结果'):
print(res.text)
# 获取货币list
@allure.epic('实现fecmall从登录到获取语言与货币list的流程')
@allure.feature('基于access-token的数据获取')
@allure.story('实现fecmall获取货币list')
@allure.title('获取货币list')
@allure.step('调用货币接口')
def test_money(api):
with allure.step('请求获取货币list操作'):
res = api.do_get(path='/v1/currency')
with allure.step('展示响应结果'):
print(res.text)
def test_end(clear):
pass
if __name__ == '__main__':
pytest.main(['-sv', '--alluredir=../allure_report/'])
os.system('allure generate ../allure_report -o ../report --clean')
test_data
login.yaml
-
request_data:
path: v1/account/login
data:
username: admin
password: admin123
expected: success