table of Contents
Python Interface Testing Course (Day 1)-Python Basic
Python Interface Testing Course (Day 2 )-Interface Testing Quick Practice
Python Interface Testing Course (Day 3 )-Interface Security Verification, Parameterization and Assertion
Python Interface Testing Course (Part 1 Four days)-Interface test framework implementation
PDF Download: Link: https://pan.baidu.com/s/1x3_LYq23F_1LviGVbRNFXw Password: xrcj
For more learning materials, please add the author WeChat: lockingfree to get
Day 4: Python interface testing framework
What is a frame
Current mainstream interface test solution
- Tool pie
- Java Pie
- Python Pie
- Interface platform
Frame type
- Record playback
- Data-driven
- Behavior-driven
Layering and planning of the framework
Frame layering
- Presentation layer: (user interface)
- Business logic layer: (read data, configure and assemble and send requests) + execution control layer (pytest)
- Data layer: (configuration read / data read / database connection / other (log / email)
Framework planning
- case: test case directory
- user: (user module)
- test_user.py: test case
- case.py: use case public method
- user: (user module)
- data: data file directory
- test_user_data.xlsx: test case data file
- conf: configuration file directory
- default.conf: default configuration file
- report: The path to save the report generated by pytest
- log: log save path, generate log by day
- common: common method directory
- config.py: read configuration file
- data.py: data file reading
- db.py: database connection
- log.py: log configuration
- send_email.py: send mail configuration
Framework implementation
conf / default.conf: presentation layer-project configuration file
[runtime]
log_level=debug
report_dir=report
log_dir=log
timeout=10
[server]
test = http://127.0.0.1:5000
stage = http://127.0.0.1:6000
prod = http://127.0.0.1:7000
[db_test]
host = localhost
port = 3307
db = api
user = root
passwd =
[db_stage]
[db_prod]
[email]
server = smtp.sina.com
user = [email protected]
pwd = ******
subject = Api Test Ressult
receiver = [email protected]
data / test_user_data.xlsx: presentation layer-use case data file
- reg table (sheet named reg)
TestCase | Url | Method | DataType | Data | Code | Msg |
---|---|---|---|---|---|---|
test_reg_normal | /api/user/reg/ | POST | JSON | {"name": "{NAME}", "passwd": "123456"} | 100000 | success |
- login table (sheet named login)
TestCase | Url | Method | DataType | Data | ResponseText |
---|---|---|---|---|---|
test_login_normal | /api/user/login/ | POST | FORM | {"name": "张三", "passwd": "123456"} | login successful |
- SQL table (sheet named SQL)
checkUser | select * from user where name={NAME} |
---|---|
checkUserPasswd | select * from user where name={NAME} and passwd={PASSWD} |
common / config.py: data layer-config file reading
"""
1. 从配置文件中获取各个段信息
2. 返回一个项目的绝对路径
"""
import os
import configparser
# 相对导入包的问题
pro_path = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
class Config(object):
def __init__(self, filename="default.conf"):
self.cf = configparser.ConfigParser()
self.cf.read(os.path.join(pro_path,"conf",filename))
def get_runtime(self, option):
return self.cf.get("runtime", option)
def get_server(self, option):
return self.cf.get("server", option)
def get_db_test(self, option):
return self.cf.get("db_test", option)
def get_email(self, option):
return self.cf.get("email",option)
if __name__ == "__main__":
c = Config()
print(c.get_runtime("log_level"))
print(c.get_server("test"))
data.py: Data layer-data file reading
"""
1. 从Excel中读取接口的数据
2. 读取Sql命令
"""
import xlrd
import sys
import os
sys.path.append("..")
from common.config import pro_path
class Data(object):
def __init__(self, filename):
data_file_path = os.path.join(pro_path,"data",filename)
self.wb = xlrd.open_workbook("../data/test_user_data.xlsx")
def get_case(self,sheet_name, case_name):
sh = self.wb.sheet_by_name(sheet_name)
for i in range(1, sh.nrows):
if sh.cell(i,0).value == case_name:
return sh.row_values(i)
print("用例名未找到")
return None
def get_sql(self, sql_name):
sh = self.wb.sheet_by_name("SQL")
for i in range(sh.nrows):
if sh.cell(i,0).value == sql_name:
return sh.cell(i,1).value
print("sql未找到")
return None
if __name__ == "__main__":
d = Data("test_user_data.xlsx")
print(d.get_case("reg","test_reg_normal"))
print(d.get_sql("checkUser"))
db.py: data layer-database connection
"""
1. 从配置文件中读取数据库配置
2. 连接数据库
3. 执行sql并返回所有结果
"""
import sys
import pymysql
sys.path.append("..")
from common.config import Config
class DB(object):
def __init__(self):
c = Config()
self.conn = pymysql.connect(host=c.get_db_test("host"),
port=int(c.get_db_test("port")),
db=c.get_db_test("db"),
user=c.get_db_test("user"),
passwd=c.get_db_test("passwd"),
charset="utf8")
self.cur = self.conn.cursor()
def do_sql(self, sql):
self.cur.execute(sql)
return self.cur.fetchall()
def __del__(self):
self.cur.close()
self.conn.close()
if __name__ == "__main__":
db = DB()
print(db.do_sql("select * from user"))
log.py: data layer-log configuration
"""
1. 配置log输出格式 time - loglevel - file - func - line - msg
2. 支持输出到log文件及屏幕
3. 支持返回一个logger,让其他模块调用
"""
import sys
sys.path.append("..")
from common.config import Config, pro_path
import time
import logging
import os
class Log():
@classmethod
def config_log(cls):
cf = Config()
log_dir = os.path.join(pro_path, cf.get_runtime("log_dir"))
today = time.strftime("%Y%m%d", time.localtime(time.time()))
log_file = os.path.join(log_dir, today+".log")
# 获取一个标准的logger, 配置loglevel
cls.logger = logging.getLogger()
cls.logger.setLevel(eval("logging." + cf.get_runtime("log_level").upper()))
# 建立不同handler
fh = logging.FileHandler(log_file, mode="a",encoding=‘utf-8’)
ch = logging.StreamHandler()
# 定义输出格式
ft = logging.Formatter("%(asctime)s - %(filename)s[line:%(lineno)d] - %(levelname)s: %(message)s")
fh.setFormatter(ft)
ch.setFormatter(ft)
# 把定制handler 添加到我们logger
cls.logger.addHandler(fh)
cls.logger.addHandler(ch)
@classmethod
def get_logger(cls):
cls.config_log()
return cls.logger
if __name__ == "__main__":
l= Log.get_logger()
l.info("abc")
l.debug("hello, debug")
send_email.py: data layer-mail server connection
"""
1. 从配置文件中读取stmp配置
2. 从report文件夹下打开report.html,发送邮件
"""
import smtplib
from email.mime.text import MIMEText
import os
import sys
sys.path.append("..")
from common.config import Config, pro_path
from common.log import Log
def send_email(report_name):
cf = Config()
logger = Log.get_logger()
report_file = os.path.join(pro_path, cf.get_runtime("report_dir"),report_name)
with open(report_file, "rb") as f:
body = f.read()
# 格式化email正文
msg = MIMEText(body, "html", "utf-8")
# 配置email头
msg["Subject"] = cf.get_email("subject")
msg["From"] = cf.get_email("user")
msg["To"] = cf.get_email("receiver")
# 连接smtp服务器,发送邮件
smtp = smtplib.SMTP()
smtp.connect(cf.get_email("server"))
smtp.login(cf.get_email("user"),cf.get_email("pwd"))
smtp.sendmail(cf.get_email("user"), cf.get_email("receiver"), msg.as_string())
print("邮件发送成功")
if __name__ == "__main__":
send_email("report.html")
case / case.py: Business logic layer, execute encapsulation method for use cases
"""
1. 加载数据
2. 发送接口
3. 为用例封装一些方法
"""
import sys
sys.path.append("..")
from common.log import Log
from common.config import Config
from common.db import DB
from common.data import Data
import json
import requests
class Case(object):
def __init__(self):
self.logger = Log.get_logger()
self.cf = Config()
def load_data(self, data_file):
self.data = Data(data_file)
def set_env(self, env):
self.env = env
def run_case(self, sheet_name, case_name, var={}):
case_data = self.data.get_case(sheet_name, case_name)
url = self.cf.get_server(self.env) + case_data[1]
data = case_data[4].format(**var)
if case_data[3].lower() == "form":
data = json.loads(data)
headers = {}
else:
headers = {"content-type": "application/json"}
if case_data[2].lower() == "get":
resp = requests.get(url=url)
else:
resp = requests.post(url=url, headers=headers, data=data)
return resp.text
def check_response(self):
pass
def check_db(self, sql_name, vars={}):
sql = self.data.get_sql(sql_name).format(**vars)
return self.db.exec_sql(sql)
if __name__ == "__main__":
c = Case()
c.set_env("test")
c.load_data("test_user_data.xlsx")
r = c.run_case("login", "test_login_normal")
print(r)
case / user / test_user.py: presentation layer: test case script
import sys
import random
import pytest
sys.path.append("../..")
from case.case import Case
case = Case()
def setup_module(module):
case.set_env('dev')
case.load_data('test_user_data.xlsx')
def test_login_normal():
result case.run("login", "test_login_normal")
if __name__ == '__main__':
pytest.main(["-q", "test_user.py"])
run_all.py: presentation layer: execute all use case entries
import os
import time
from util.config import Config
from util.e_mail import send_email
import pytest
def main():
cf = Config()
report_dir = cf.get_report_dir()
now = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
report_name = os.path.join(report_dir, 'report_' + now + '.html')
pytest.main(["-q", "case", "--html=" + report_name])
send_email(report_name)
if __name__ == '__main__':
main()