1. 封裝post和get方法:方便在使用requests模塊發送請求時,僅調用一個方法即可
備註:文件名均在腳本中的頂部,用”fileName“標識
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# fileName: run_method.py
import requests
class RunMethod(object):
def post_main(self, url, headers, data):
# 忽略不安全的請求警告信息
requests.packages.urllib3.disable_warnings()
# 遇到requests的ssl驗證,若想直接跳過不驗證,設置verify=False即可
response = requests.post(url=url, headers=headers, data=data, verify=False)
return response
def get_main(self, url, headers, data=None):
# 忽略不安全的請求警告信息
requests.packages.urllib3.disable_warnings()
response = requests.get(url=url, headers=headers, data=data, verify=False)
return response
def run_main(self, method, url, headers, data=None):
# 忽略不安全的請求警告信息
requests.packages.urllib3.disable_warnings()
requests.adapters.DEFAULT_RETRIES = 5
if method == "Post":
res = self.post_main(url, headers, data)
elif method == "Get":
res = self.get_main(url, headers, data)
# 將響應的的數據以字典數據結構和json數據格式返回
return res.json()
2. 存儲接口信息:使用yml文件作爲配置文件,存儲每一個接口信息,主要包括”接口名稱、method、url、data和headers“
# fileName: api_config.yml
host: https://XXX.com
login:
name: 【登錄】手機號碼登錄
method: Post
url: /v1/login/
data:
phone_country: 86
phone_number: 1210000000
password: 123456
device_id: XXX
device_name: Iphone8plus
device_pubkey: XXX
headers:
Content-Type: application/x-www-form-urlencoded
Authorization: Basic XXX
asset_main:
name: 【資產】用戶資產列表頁
method: Get
url: /v2/main/
headers:
Authorization: Bearer
app-version: 4.8.0
device-id: XXX
lend:
name: 發送請求
method: Post
url: /v1/lend/
data:
payment_password: 123456
amount: 100
pledge_source: 1
headers:
Content-Type: application/x-www-form-urlencoded
Authorization: Bearer
device-id: XXX
app-version: 4.8.0
3. 封裝登錄和其他方法:
1)登錄方法用於獲取並存儲token,存儲至access_token.yml中;
2)參數”api_name“的取值是配置文件api_config.yml中的接口名稱,比如:login、asset_main和loan_lend。同樣封裝了一個類ReadYaml,方法是取配置文件中各接口的”method、url、data和headers“等;
3)除了登錄接口,其他接口的headers均需要token值,所以在處理headers時要區分登錄接口和其他接口;
4)建議:添加異常處理捕獲異常,輸出自定義的錯誤信息。
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# fileName: app_api.py
from common.run_method import RunMethod
from common.read_info import ReadYaml
from common.get_log import get_log
from common.deal_token import write_token
import json
class AllApi(object):
def __init__(self):
self.run = RunMethod()
self.read = ReadYaml()
self.logger = get_log()
# 登錄,獲取token
def login(self, api_name):
try:
# 獲取接口請求參數
method = self.read.get_method(api_name)
url = self.read.get_url(api_name)
data = self.read.get_data(api_name)
headers = self.read.get_headers(api_name)
response = self.run.run_main(method, url, headers, data)
# 把token值寫到配置文件access_token.yml中,供其他接口調用
write_token(response)
print(json.dumps(response, indent=2, ensure_ascii=False, sort_keys=False))
return response
except Exception as e:
self.logger.info("接口訪問出錯啦~ %s" % e)
# 其他接口請求封裝
def send_request(self, api_name):
try:
# 獲取接口請求參數
method = self.read.get_method(api_name)
url = self.read.get_url(api_name)
headers = self.read.get_headers(api_name)
# 區分Get和Post方法
if method == "Get":
response = self.run.run_main(method, url, headers)
elif method == "Post":
data = self.read.get_data(api_name)
response = self.run.run_main(method, url, headers, data)
# print(json.dumps(response, indent=2, ensure_ascii=False, sort_keys=False))
print(json.dumps(response, indent=2, ensure_ascii=False, sort_keys=False))
print(response["success"])
return response
except Exception as e:
self.logger.info("接口訪問出錯啦~ %s" % e)
4. 使用Pytest管理測試用例:
1)在執行所有用例之前先執行登錄接口,獲取token。所以把登錄接口的請求放在conftest.py文件中
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# fileName: conftest.py
from API.all_api import AllApi
import pytest
from common.get_log import get_log
logger = get_log()
# 在執行所有用例之前先執行登錄接口,獲取token
@pytest.fixture(scope="session")
def init_token():
# 正確郵箱/手機號和密碼登錄
logger.info("\n ============================= 在所有用例執行之前,生成token =============================")
all_login = AllApi()
all_login.login("login_sandbox_phoneNumber")
2) 把每個功能模塊封裝成一個類,每個用例封裝成一個方法。例如資產模塊的用例如下:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# fileName: test_asset.py
from API.all_api import AllApi
import pytest
from common.get_log import get_log
logger = get_log()
# 資產模塊的測試用例
@pytest.mark.usefixtures("init_token")
class TestAsset(object):
@pytest.fixture(scope="class")
def init_asset(self):
logger.info("\n ==============================【資產】測試用例開始 ==============================")
all_request = AllApi()
return all_request
@pytest.mark.parametrize("api_name", ["asset_main"])
def test_asset_main(self, api_name, init_asset):
print("\n 用例名稱:獲取資產列表信息\n")
res = init_asset.send_request(api_name)
# 斷言1:success的值爲true
assert res['success'] is True, "success的值爲: %s" % res['success']
# 斷言2:total_value的值不爲空
assert res['result']['assets']['total_value'] is not None, "total_value的值爲:%s" % res['result']['assets']['total_value']
if __name__ == "__main__":
# pytest.main(['-v', 'test_asset.py'])
pytest.main(['-v', 'test_asset.py', '--html=report/asset_report.html', '--self-contained-html'])
5. 添加日誌模塊:
1)使用配置文件配置loggers、handlers和formatters(日誌器、處理器和格式器),文件名稱是log.conf
[loggers]
keys=root,main
[logger_root]
level=DEBUG
handlers=consoleHandler,fileHandler
[logger_main]
level=DEBUG
qualname=main
handlers=fileHandler
[handlers]
keys=consoleHandler,fileHandler
[handler_consoleHandler]
class=StreamHandler
level=DEBUG
formatter=fmt
args=(sys.stdout,)
[handler_fileHandler]
class=logging.handlers.RotatingFileHandler
level=DEBUG
formatter=fmt
args=('../log/Wallet_API_Test.log','a')
[formatters]
keys=fmt
[formatter_fmt]
format=%(asctime)s - %(filename)s - %(levelname)s - [line:%(lineno)d] - %(message)s
2)使用fileConfig()函數讀取日誌配置文件
# fileName: get_log.py
import logging.config
import logging
# 讀取日誌配置文件
def get_log():
con_log = "../configs/log.conf"
logging.config.fileConfig(con_log)
log = logging.getLogger()
return log
6. 測試報告:
1)安裝pytest-html插件。也可以使用allure插件生成測試報告,但是如果pytest版本過高,就無法識別allure插件
2)添加“--self-contained-html”可以整合樣式文件到html文檔中,方便之後發送測試報告到郵箱
pytest.main(['-v', '--html=report/all_report.html', '--self-contained-html'])
7. 測試報告發送至郵箱:
#!/usr/bin/env python
# -*- coding:utf-8 -*-
# fileName: run_email.py
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.header import Header
import smtplib
# 定義發郵件
def send_mail(file_path):
f = open(file_path, 'rb')
mail_body = f.read()
f.close()
smtpserver = 'smtp.qq.com'
# 設置登錄郵箱的賬號和授權密碼
user = '[email protected]'
password = ""
sender = '[email protected]'
# 可添加多個收件人的郵箱
receives = ['[email protected]']
# 構造郵件對象
msg = MIMEMultipart('mixed')
# 定義郵件的標題
subject = '接口自動化測試報告'
# HTML郵件正文,定義成字典
msg['Subject'] = Header(subject, "utf-8")
msg['From'] = sender
msg['To'] = ','.join(receives)
# 構造文字內容
text_plain = MIMEText("附件是最新的接口自動化測試報告,請查看", 'html', 'utf-8')
msg.attach(text_plain)
# 構造附件
text_attr = MIMEText(mail_body, 'base64', 'utf-8')
text_attr["Content-Type"] = 'application/octet-stream'
text_attr['Content-Disposition'] = 'attachment; filename = "test.html"'
msg.attach(text_attr)
# 郵箱設置時勾選了SSL加密連接,進行防垃圾郵件,SSL協議端口號要使用465
smtp = smtplib.SMTP_SSL(smtpserver, 465)
# 向服務器標識用戶身份
smtp.helo(smtpserver)
# 向服務器返回確認結果
smtp.ehlo(smtpserver)
# 登錄郵箱的賬號和授權密碼
smtp.login(user, password)
print("開始發送郵件...")
# 開始進行郵件的發送,msg表示已定義的字典
smtp.sendmail(sender, receives, msg.as_string())
smtp.quit()
print("已發送郵件")
if __name__ == "__main__":
report = "../testcase/report/report.html"
send_mail(report)
未完待續......