介绍:
common:存放一些共通的方法
result:执行过程中生成的文件夹,里面存放每次测试的结果
testCase:用于存放具体的测试
case testFile:存放测试过程中用到的文件,包括上传的文件,测试用例以及
数据库的sql语句 caselist:txt文件,配置每次执行的case名称
config:配置一些常量,例如数据库的相关信息,接口的相关信息等
runAll:用于执行case
config.ini
[DATABASE]
host = 50.23.190.57
username = xxxxxx
password = ******
port = 3306
database = databasename
[HTTP]
# 接口的url
baseurl = http://xx.xxxx.xx
port = 8080
timeout = 1.0
[EMAIL]
mail_host = smtp.163.com
mail_user = [email protected]
mail_pass = *********
mail_port = 25
sender = [email protected]
receiver = [email protected]/[email protected]
subject = python
content = "All interface test has been complited\nplease read the report file about the detile of result in the attachment."
testuser = Someone
on_off = 1
readConfig.py
import os
import codecs
import configparser
proDir = os.path.split(os.path.realpath(__file__))[0]
configPath = os.path.join(proDir, "config.ini")
class ReadConfig:
def __init__(self):
fd = open(configPath)
data = fd.read()
# remove BOM
if data[:3] == codecs.BOM_UTF8:
data = data[3:]
file = codecs.open(configPath, "w")
file.write(data)
file.close()
fd.close()
self.cf = configparser.ConfigParser()
self.cf.read(configPath)
def get_email(self, name):
value = self.cf.get("EMAIL", name)
return value
def get_http(self, name):
value = self.cf.get("HTTP", name)
return value
def get_db(self, name):
value = self.cf.get("DATABASE", name)
return value
import logging
from datetime import datetime
import threading
class Log:
def __init__(self):
global logPath, resultPath, proDir
proDir = readConfig.proDir
resultPath = os.path.join(proDir, "result")
# create result file if it doesn't exist
if not os.path.exists(resultPath):
os.mkdir(resultPath)
# defined test result file name by localtime
logPath = os.path.join(resultPath, str(datetime.now().strftime("%Y%m%d%H%M%S")))
# create test result file if it doesn't exist
if not os.path.exists(logPath):
os.mkdir(logPath)
# defined logger
self.logger = logging.getLogger()
# defined log level
self.logger.setLevel(logging.INFO)
# defined handler
handler = logging.FileHandler(os.path.join(logPath, "output.log"))
# defined formatter
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
# defined formatter
handler.setFormatter(formatter)
# add handler
self.logger.addHandler(handler)
class MyLog:
log = None
mutex = threading.Lock()
def __init__(self):
pass
@staticmethod
def get_log():
if MyLog.log is None:
MyLog.mutex.acquire()
MyLog.log = Log()
MyLog.mutex.release()
return MyLog.log
configHttp.py
import requests
import readConfig as readConfig
from common.Log import MyLog as Log
localReadConfig = readConfig.ReadConfig()
class ConfigHttp:
def __init__(self):
global host, port, timeout
host = localReadConfig.get_http("baseurl")
port = localReadConfig.get_http("port")
timeout = localReadConfig.get_http("timeout")
self.log = Log.get_log()
self.logger = self.log.get_logger()
self.headers = {}
self.params = {}
self.data = {}
self.url = None
self.files = {}
def set_url(self, url):
self.url = host + url
def set_headers(self, header):
self.headers = header
def set_params(self, param):
self.params = param
def set_data(self, data):
self.data = data
def set_files(self, file):
self.files = file
# defined http get method
def get(self):
try:
response = requests.get(self.url, params=self.params, headers=self.headers, timeout=float(timeout))
# response.raise_for_status()
return response
except TimeoutError:
self.logger.error("Time out!")
return None
# defined http post method
def post(self):
try:
response = requests.post(self.url, headers=self.headers, data=self.data, files=self.files, timeout=float(timeout))
# response.raise_for_status()
return response
except TimeoutError:
self.logger.error("Time out!")
return None
get方法
对于requests提供的get方法,有几个常用的参数:url:显而易见,就是接口的地址url啦
headers:定制请求头(headers),例如:content-type =
application/x-www-form-urlencodedparams:用于传递测试接口所要用的参数,这里我们用python中的字典形式(key:value)进行参数的传递。
timeout:设置接口连接的最大时间(超过该时间会抛出超时错误)
举个栗子:
header={‘content-type’: application/x-www-form-urlencoded} param={‘user_id’: 123456,‘email’: 123456@163.com} timeout=0.5 requests.get(url, headers=header, params=param, timeout=timeout)
post方法
与get方法类似,只要设置好对应的参数,就可以了。下面就直接举个栗子,直接上代码吧:header={‘content-type’: application/x-www-form-urlencoded} data={‘email’: 123456@163.com,‘password’: 123456} timeout=0.5 requests.post(url, headers=header, data=data, timeout=timeout
依然只说常用的返回值的操作。
text:获取接口返回值的文本格式
json():获取接口返回值的json()格式
status_code:返回状态码(成功为:200)
headers:返回完整的请求头信息(headers[‘name’]:返回指定的headers内容)
encoding:返回字符编码格式
url:返回接口的完整url地址
common.py
import os
from xlrd import open_workbook
from xml.etree import ElementTree as ElementTree
from common.Log import MyLog as Log
localConfigHttp = configHttp.ConfigHttp()
log = Log.get_log()
logger = log.get_logger()
# 从excel文件中读取测试用例
def get_xls(xls_name, sheet_name):
cls = []
# get xls file's path
xlsPath = os.path.join(proDir, "testFile", xls_name)
# open xls file
file = open_workbook(xlsPath)
# get sheet by name
sheet = file.sheet_by_name(sheet_name)
# get one sheet's rows
nrows = sheet.nrows
for i in range(nrows):
if sheet.row_values(i)[0] != u'case_name':
cls.append(sheet.row_values(i))
return cls
# 从xml文件中读取sql语句
database = {}
def set_xml():
if len(database) == 0:
sql_path = os.path.join(proDir, "testFile", "SQL.xml")
tree = ElementTree.parse(sql_path)
for db in tree.findall("database"):
db_name = db.get("name")
# print(db_name)
table = {}
for tb in db.getchildren():
table_name = tb.get("name")
# print(table_name)
sql = {}
for data in tb.getchildren():
sql_id = data.get("id")
# print(sql_id)
sql[sql_id] = data.text
table[table_name] = sql
database[db_name] = table
def get_xml_dict(database_name, table_name):
set_xml()
database_dict = database.get(database_name).get(table_name)
return database_dict
def get_sql(database_name, table_name, sql_id):
db = get_xml_dict(database_name, table_name)
sql = db.get(sql_id)
return sql
上面就是我们common的两大主要内容了,什么?还不知道是什么吗?让我告诉你吧。
我们利用xml.etree.Element来对xml文件进行操作,然后通过我们自定义的方法,根据传递不同的参数取得不(想)同(要)的值。
利用xlrd来操作excel文件,注意啦,我们是用excel文件来管理测试用例的。
听起来会不会有点儿懵,小编刚学时也很懵,看文件就好理解了。
excel文件:
xml文件:
接下来,我们看看数据库和发送邮件吧(也可根据需要,不写该部分内容)
先看老朋友“数据库”吧。
请朋友们先把pymysql装起来:
pip install pymysql
这次使用的是MySQL数据库,所以我们就以它为例吧。
import pymysql
import readConfig as readConfig
from common.Log import MyLog as Log
localReadConfig = readConfig.ReadConfig()
class MyDB:
global host, username, password, port, database, config
host = localReadConfig.get_db("host")
username = localReadConfig.get_db("username")
password = localReadConfig.get_db("password")
port = localReadConfig.get_db("port")
database = localReadConfig.get_db("database")
config = {
'host': str(host),
'user': username,
'passwd': password,
'port': int(port),
'db': database
}
def __init__(self):
self.log = Log.get_log()
self.logger = self.log.get_logger()
self.db = None
self.cursor = None
def connectDB(self):
try:
# connect to DB
self.db = pymysql.connect(**config)
# create cursor
self.cursor = self.db.cursor()
print("Connect DB successfully!")
except ConnectionError as ex:
self.logger.error(str(ex))
def executeSQL(self, sql, params):
self.connectDB()
# executing sql
self.cursor.execute(sql, params)
# executing by committing to DB
self.db.commit()
return self.cursor
def get_all(self, cursor):
value = cursor.fetchall()
return value
def get_one(self, cursor):
value = cursor.fetchone()
return value
def closeDB(self):
self.db.close()
print("Database closed!")
configEmail.py
import os
import smtplib
from email.mime.multipart import MIMEMultipart
from email.mime.text import MIMEText
from datetime import datetime
import threading
import readConfig as readConfig
from common.Log import MyLog
import zipfile
import glob
localReadConfig = readConfig.ReadConfig()
class Email:
def __init__(self):
global host, user, password, port, sender, title, content
host = localReadConfig.get_email("mail_host")
user = localReadConfig.get_email("mail_user")
password = localReadConfig.get_email("mail_pass")
port = localReadConfig.get_email("mail_port")
sender = localReadConfig.get_email("sender")
title = localReadConfig.get_email("subject")
content = localReadConfig.get_email("content")
self.value = localReadConfig.get_email("receiver")
self.receiver = []
# get receiver list
for n in str(self.value).split("/"):
self.receiver.append(n)
# defined email subject
date = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
self.subject = title + " " + date
self.log = MyLog.get_log()
self.logger = self.log.get_logger()
self.msg = MIMEMultipart('mixed')
def config_header(self):
self.msg['subject'] = self.subject
self.msg['from'] = sender
self.msg['to'] = ";".join(self.receiver)
def config_content(self):
content_plain = MIMEText(content, 'plain', 'utf-8')
self.msg.attach(content_plain)
def config_file(self):
# if the file content is not null, then config the email file
if self.check_file():
reportpath = self.log.get_result_path()
zippath = os.path.join(readConfig.proDir, "result", "test.zip")
# zip file
files = glob.glob(reportpath + '\*')
f = zipfile.ZipFile(zippath, 'w', zipfile.ZIP_DEFLATED)
for file in files:
f.write(file)
f.close()
reportfile = open(zippath, 'rb').read()
filehtml = MIMEText(reportfile, 'base64', 'utf-8')
filehtml['Content-Type'] = 'application/octet-stream'
filehtml['Content-Disposition'] = 'attachment; filename="test.zip"'
self.msg.attach(filehtml)
def check_file(self):
reportpath = self.log.get_report_path()
if os.path.isfile(reportpath) and not os.stat(reportpath) == 0:
return True
else:
return False
def send_email(self):
self.config_header()
self.config_content()
self.config_file()
try:
smtp = smtplib.SMTP()
smtp.connect(host)
smtp.login(user, password)
smtp.sendmail(sender, self.receiver, self.msg.as_string())
smtp.quit()
self.logger.info("The test report has send to developer by email.")
except Exception as ex:
self.logger.error(str(ex))
class MyEmail:
email = None
mutex = threading.Lock()
def __init__(self):
pass
@staticmethod
def get_email():
if MyEmail.email is None:
MyEmail.mutex.acquire()
MyEmail.email = Email()
MyEmail.mutex.release()
return MyEmail.email
if __name__ == "__main__":
email = MyEmail.get_email()
runAll.py
import unittest
import HTMLTestRunner
def set_case_list(self):
fb = open(self.caseListFile)
for value in fb.readlines():
data = str(value)
if data != '' and not data.startswith("#"):
self.caseList.append(data.replace("\n", ""))
fb.close()
def set_case_suite(self):
self.set_case_list()
test_suite = unittest.TestSuite()
suite_model = []
for case in self.caseList:
case_file = os.path.join(readConfig.proDir, "testCase")
print(case_file)
case_name = case.split("/")[-1]
print(case_name+".py")
discover = unittest.defaultTestLoader.discover(case_file, pattern=case_name + '.py', top_level_dir=None)
suite_model.append(discover)
if len(suite_model) > 0:
for suite in suite_model:
for test_name in suite:
test_suite.addTest(test_name)
else:
return None
return test_suite
def run(self):
try:
suit = self.set_case_suite()
if suit is not None:
logger.info("********TEST START********")
fp = open(resultPath, 'wb')
runner = HTMLTestRunner.HTMLTestRunner(stream=fp, title='Test Report', description='Test Description')
runner.run(suit)
else:
logger.info("Have no case to test.")
except Exception as ex:
logger.error(str(ex))
finally:
logger.info("*********TEST END*********")
# send test report by email
if int(on_off) == 0:
self.email.send_email()
elif int(on_off) == 1:
logger.info("Doesn't send report email to developer.")
else:
logger.info("Unknow state.")
testCase文件夹下,存放我们写的具体的测试case啦,上面这些就是小编写的一些。注意喽,所有的case名称都要以test开头来命名哦,这是因为,unittest在进行测试时会自动匹配testCase文件夹下面所有test开头的.py文件
testFile文件夹下,放置我们测试时用来管理测试用例的excel文件和用于数据库查询的sql语句的xml文件哦。
最后就是caselist.txt文件了,就让你们瞄一眼吧:
转载:https://my.oschina.net/u/3041656/blog/820023
本文是单纯欣赏 转载记录,非原创。在这里插入代码片