前言
作为软件开发过程中一个非常重要的环节,软件测试越来越成为软件开发商和用户关注的焦点。完善的测试是软件质量的保证,因此软件测试就成了一项重要而艰巨的工作。要做好这项工作当然也绝非易事。
下面我着重谈谈自己在做软件测试工作中总结出来的一些经验和技巧,以供大家参考。
先在window安装响应的环境依赖
注意:可能还需要一些依赖的东西,项目步骤里会依据需要进行安装
在pycharm中开发构建项目结构
从这一步开始正式编写代码
封装http请求的公共能力(封装request库,变成自己的公共处理能力),放到common目录下。
import requests
import urllib3
# from urllib3.exceptions import InsecureRequestWarning
urllib3.disable_warnings()
# 加这句不会报错(requests证书警告)
# requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
class HTTPRequests(object):
def __init__(self, url):
self.url = url
self.req = requests.session()
# 依据自己公司的请求头默认值配置
self.head = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64; Trident/7.0; rv:11.0) like Gecko',
'Accept': 'image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xaml+xml, '
'application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, '
'application/msword, */*',
'Accept-Language': 'zh-CN'}
# 封装自己的get请求,获取资源
def get(self, uri='', params='', data='', headers=None, cookies=None, verify=False):
if headers is None:
headers = self.head
# print("请求头是:{}".format(headers))
url = self.url + uri
response = self.req.get(url, params=params, data=data, headers=headers, cookies=cookies, verify=verify)
return response
# 封装自己的post请求,获取资源
def post(self, uri='', params='', data='', headers=None, cookies=None, verify=False):
if headers is None:
headers = self.head
url = self.url + uri
response = self.req.post(url, params=params, data=data, headers=headers, cookies=cookies, verify=verify)
return response
# 封装自己的put请求,获取资源
def put(self, uri='', params='', data='', headers=None, cookies=None, verify=False):
if headers is None:
headers = self.head
url = self.url + uri
response = self.req.put(url, params=params, data=data, headers=headers, cookies=cookies, verify=verify)
return response
# 封装自己的delete请求,获取资源
def delete(self, uri='', params='', data='', headers=None, cookies=None, verify=False):
if headers is None:
headers = self.head
url = self.url + uri
response = self.req.delete(url, params=params, data=data, headers=headers, cookies=cookies, verify=verify)
return response
这个步骤的目的有三个
import enum
class URLConf(enum.Enum):
"""环境配置信息"""
url_mapping = {
'dev': 'https://www.dev.com',
'test': 'https://www.test.com',
'prod': 'https://www.prod.com'
}
# token固定的用户名密码,固定用"/"分割用户名和密码
email_user = {
'dev': '[email protected]',
'test': '[email protected]/96e79218965eb72c92a549dd5a330112',
'prod': '[email protected]'
}
login_uri = r'/api/auth/login/account/v1'
1、pytest_addoption,设置了只允许输入dev/test/prod三个参数,以区分测试、开发、生产三个环境
2、get_env的fixture,它的作用是你在命令行执行接口自动化时,可以输入--env test将对应的环境信息传入进去
3、http的fixture,这里依据--env test传入的环境信息,去枚举类里获取对应环境的URL,然后返回一个http的session,供测试案例使用
4、get_token_head,依据--env test传入的环境信息,调用获取token方法,并将token放置到请求头head里返回(token一般放在请求头里,这里依据自己公司的请求,返回对应的token信息就可以了)
import logging
import os
import pytest
from common.http_request import HTTPRequests
from config.url_config import URLConf
datadir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "test_data")
logger = logging.getLogger('conftest日志')
def pytest_addoption(parser):
# choices 只允许输入的值的范围
parser.addoption(
"--env", action="store", default='test', choices=['dev', 'test', 'prod'], help="set env"
)
# 获取命令行参数的fixture
@pytest.fixture(scope='session')
def get_env(request):
# print("fixutre..................")
return request.config.getoption('--env')
# 声明一个返回http请求对象的fixture,所有用例在一个session中
# @pytest.fixture(scope='module', autouse=True)
@pytest.fixture(autouse=True)
def http(request):
env = request.getfixturevalue("get_env")
url_mapping = URLConf.url_mapping.value
url = url_mapping.get(f'{env}')
http = HTTPRequests(url)
return http
@pytest.fixture(scope='session')
def get_token_head(request):
env = request.getfixturevalue("get_env")
url_mapping = URLConf.url_mapping.value
url = url_mapping.get(f'{env}')
http = HTTPRequests(url)
user = URLConf.email_user.value
user_list = user.get(f'{env}').split("/")
username = user_list[0]
password = user_list[1]
param = {'clientType': 2,
'language': 'en',
'loginId': username,
'loginPassword': password}
logger.info("请求的url=={}".format(url))
response = http.post(uri=r'/api/auth/login/account/v1', data=param)
logger.info("获取的返回值是:".format(response.text))
token = None
if response.status_code == 200:
token = response.json().get('result')['token']
else:
token = 'get token fail'
head = {
'User-Agent': 'Mozilla/5.0 (Windows NT 6.2; WOW64; Trident/7.0; rv:11.0) like Gecko',
'Accept': 'image/gif, image/jpeg, image/pjpeg, application/x-ms-application, application/xaml+xml, '
'application/x-ms-xbap, application/vnd.ms-excel, application/vnd.ms-powerpoint, '
'application/msword, */*',
'Accept-Language': 'zh-CN',
'Authorization': token}
yield head
我们的测试数据是放在excel中,注意,这里有prod\test\dev三个目录,对应三个环境的测试数据,我这里只创建了test测试环境的测试数据。这里的测试数据需要包含两部分:
那么这时候,就需要一个读取excel的公共方法了,放到common里
# 创建解析excel的方法
import logging
from openpyxl import load_workbook
logger = logging.getLogger("读取excel")
class ParseExcel(object):
def __init__(self, excelPath, sheetName):
self.wb = load_workbook(excelPath)
self.sheet = self.wb[sheetName]
self.maxRowNum = self.sheet.max_row
# 依据传入的数字,决定获取几列excel数据
def getDataFromSheet(self, num):
dataList = []
for line in self.sheet.rows:
tmplist = []
for i in range(num):
tmplist.append(line[i].value)
dataList.append(tmplist)
print("dadddddd:{}".format(dataList))
return dataList[2:]
这里,还需要在test_data中,创建一个文件,为了获取前面test_data依据环境创建的dev/test或prod文件目录
注意:这里只有一个test或prod或dev的文字,是为了拼接....test_data/test目录获取对应环境的excel测试数据而使用的,每次环境切换前,需要更改这个文件,可能这并不是一个好方法,如果大家有找到更好的方法,也可以分享一下
测试案例中有几个点,需要解释一下:
1、authBaseDir,这个就是根据test_data/test拼接出来的获取测试数据的目录
2、allure.feature,在测试报告中,会展现这个接口名称,这个名称最好与你公司的开发写的接口模块保持一致,方便后续查找问题
3、allure.story 这里也要与开发写的具体某个接口的名称保持一致。
4、pytest.mark.parametrize,这里就是运用的DDT数据驱动的模式,从excel中一条一条的获取数据,然后执行同一条接口测试用例,excel中比如有3条数据,那么就表示这个案例依据每一条数据的参数,总共执行了三次
# encoding: utf-8
"""
create by Arthur
Account Api模块
"""
import logging
import os
import allure
import pytest
from common.get_data_url import get_data_url
from common.parse_excel import ParseExcel
datadir = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "test_data")
data_url = get_data_url()
# 获取到test_data\test的目录,如果是prod环境,那么就是获取test_data\prod目录
authBaseDir = os.path.join(datadir, data_url)
logger = logging.getLogger("Account Api模块日志")
@allure.feature("AccountApi模块")
@pytest.mark.webtest
class TestAccountApi(object):
"""Query Related Achievements: /api/auth/account/achievement/related/query/v1
"""
Query_Related_Achievements_dir = os.path.join(authBaseDir, 'Query_Related_Achievements.xlsx')
logger.info("Query_Related_Achievements测试数据的路径是:{}".format(Query_Related_Achievements_dir))
parse = ParseExcel(Query_Related_Achievements_dir, 'Sheet1')
Query_Related_Achievements_params = parse.getDataFromSheet(5)
@allure.story("Query Related Achievements(查询用户成就信息)")
@pytest.mark.parametrize("clientType,language,retCode,istoken,result", Query_Related_Achievements_params)
def test_001_Query_Related_Achievements(self, get_token_head, http, clientType, language, retCode, istoken, result):
uri = '/api/auth/account/achievement/related/query/v1'
params = {"clientType": clientType, "language": language}
if istoken == 'yes':
header = get_token_head
response = http.get(uri=uri, params=params, headers=header)
json_req = response.json()
logger.info("Query_Related_Achievements有token的返回值是:{}".format(json_req))
assert json_req.get('retCode') == 200
assert json_req.get('result')[0]['smallImg'] == result
else:
response = http.get(uri=uri, params=params)
json_req = response.json()
logger.info("Query_Related_Achievements没有token的返回值是:{}".format(json_req))
assert json_req.get('retCode') == 401
assert json_req.get('message') == result
写到这里,是不是发现前面的allure.feature是不是用不了呢?这是因为我们还没有集成allure进去。
1、下载allure,放到lib目录下,使你的工程具备allure的能力。
2、pip install allure-pytest 安装pytest对应的allure包
1、先在main中创建一个pytest.ini文件,设置一些执行参数
2、在main中创建执行策略
"""
所有案例执行并生成allure测试报告的执行策略
"""
import os
import sys
import threading
import pytest
sys.path.append(os.path.dirname(os.path.abspath(__file__)) + '/../')
from common.report import Report
project_root = os.path.dirname(os.path.dirname(os.path.realpath(__file__)))
report_dir = os.path.join(project_root, 'report')
# 存放测试结果的目录,会生成一推json文件
result_dir = os.path.join(report_dir, 'allure_result')
allure_report = os.path.join(report_dir, 'allure_report')
report = Report()
# 定义搜索条件,搜索所有以test开头的用例
tag = 'test'
def run_pytest():
# --clean-alluredir
# pytest.main(['-vv', '-s', '-m', 'webtest', f'--alluredir={result_dir}', '--clean-alluredir'])
# 执行前清除allure_result数据,避免生成报告时,会把上次执行的数据带进去
pytest.main(['-vv', '-s', '-k', f'{tag}', f'--alluredir={result_dir}', '--clean-alluredir'])
def general_report():
# 调用cmd方法 report.allure,根据windows或linux环境判断
# 然后执行生成报告的方法generate
# --clean 覆盖路径,将上次的结果覆盖掉
cmd = "{} generate {} -o {} --clean".format(report.allure, result_dir, allure_report)
# 执行命令行命令,并通过read()方法将命令的结果返回
print(os.popen(cmd).read())
if __name__ == '__main__':
# 创建两个线程,分别执行两个方法
run = threading.Thread(target=run_pytest)
gen = threading.Thread(target=general_report)
run.start()
# 先执行第一个线程,这个线程执行完才会执行下面的线程和主线程
run.join()
gen.start()
gen.join()
在windows下,右键执行main下面的run_test_allure_html.py(就是上一个步骤的python文件),然后打开report/allure_report/index.html看看报告是否生成成功
福利:
软件测试工程师学习资源包
这篇贴子到这里就结束了,最后,希望看这篇帖子的朋友能够有所收获。如果想以测试为长期发展职业目标,是需要时刻保持学习的,要使自己具备竞争力,无论你现在工作几年,只要行动起来,你就已经占优势了。祝大家2022年能升职加薪,没入职的就早日拿到心仪公司的offer,事事顺遂。
衷心感谢每一个认真阅读我文章的人
欢迎留言,或是关注我的专栏和我交流。