使用python搭建一个接口自动化的框架,主要实现的功能如下:
下面案例可供参考
demoauto
这个目录可以存放所有的测试脚本(针对测试用例的断言)
例子:
https://tcc.taobao.com/cc/json/mobile_tel_segment.htm?tel=XXXXXX
这是一个公共接口,可以随便使用
import unittest
import requests
class TestMobileTelSegment(unittest.TestCase):
def sendRequests(self):
self.url = "https://tcc.taobao.com/cc/json/mobile_tel_segment.htm"
self.method = "get"
self.params = "tel=157XXXXXXX87"
res = requests.request(self.method,self.url,params =self.params)
print(res.text)
return res.text
def test01case(self):
res = self.sendRequests()
expect_result = '''__GetZoneResult_ = {
mts:'15XXXXX',
province:'云南',
catName:'中国移动',
telString:'15XXXXX987',
areaVid:'3XX5',
ispVid:'3XXX39',
carrier:'云南移动'
}'''
self.assertTrue(res.replace("\n",""), expect_result.replace("\n",""))
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(TestMobileTelSegment("test01case"))
runner = unittest.TextTestRunner(verbosity=3)
runner.run(suite)
小结:
1、Unittest是python自带的模块,拥有断言的功能。使用Unittest作为测试断言,必须引入unittest模块,并让测试类继承Unittest.Testcase
2、执行测试用例可以把所有测试用例添加到一个suite里,然后去执行
如果在这个类中再编写一个test02case,则只需再runner前一行,再添加一句:suite.addTest(TestMobileTelSegment(“test02case”))
当编写大量测试脚本的时候,每一个接口都要用到发送请求,所以可以把发送请求的接口抽离出来,编写为一个公共方法
import requests as rq
class SendRequest:
def send_request(self, url, method, params="", headers=""):
res = rq.request(method, url, params=params, headers=headers)
return res.text
修改test_mobile_tel_segment.py
import unittest
import requests
from demoauto.common.sendrequest import SendRequest
class TestMobileTelSegment(unittest.TestCase):
def test01case(self):
#测试的数据
url = "https://tcc.taobao.com/cc/json/mobile_tel_segment.htm"
method = "get"
params = "tel=15XXXXXXX87"
#发送请求
res = SendRequest().send_request(url, method, params)
#断言
expect_result = '''__GetZoneResult_ = {
mts:'1XXXXX9',
province:'云南',
catName:'中国移动',
telString:'15XXXXXX7',
areaVid:'30515',
ispVid:'32XXXX9',
carrier:'云南移动'
}'''
self.assertTrue(res.replace("\n",""), expect_result.replace("\n",""))
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(TestMobileTelSegment("test01case"))
runner = unittest.TextTestRunner(verbosity=3)
runner.run(suite)
小结:
1、提取了公共方法后,使用时需要引入
用Excel编写测试用例,代码读取测试数据、请求信息后执行
import os
import openpyxl as ox
#获取当前路径:到common结束
#path = os.path.abspath(os.path.dirname(__file__))
#path = os.getcwd()
#获取当前路径的上一层路径:到demoauto
path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
class ReadExcel():
def get_workbook(self, filename):
#测试用例实际的路径
xlsPath = os.path.join(path, 'testfile', filename)
print(xlsPath)
# 打开测试用例
f = ox.load_workbook(xlsPath)
#获取当前要操作的sheet对象
return f
def get_title(self, filename):
f = self.get_workbook(filename)
sheet = f.active
#读取标题行
for row in sheet.iter_rows(max_row=1):
title_row = [cell.value for cell in row]
self.close_file(f)
return title_row
def get_data(self, filename):
f = self.get_workbook(filename)
sheet = f.active
#读取正文内容
arr = []
for row in sheet.iter_rows(min_row=2):
row_data = [cell.value for cell in row]
arr.append(row_data)
self.close_file(f)
return arr
#获取全部case内容
def get_all_cases(self) -> list:
arr = self.get_data("autotestcase.xlsx")
return arr
def get_case_by_module_name(self, modulename):
arr = self.get_data("autotestcase.xlsx")
caseinfo = []
for i in range(len(arr)):
if arr[i][1] == modulename:
caseinfo.append(arr[i])
return caseinfo
def get_case_by_case_name(self, casename):
arr = self.get_data("autotestcase.xlsx")
caseinfo = None
for i in range(len(arr)):
if arr[i][2] == casename:
caseinfo = arr[i]
return caseinfo
def close_file(self, f):
f.close()
#测试,最后运行项目时,需要注释这段代码
if __name__ == '__main__':
re = ReadExcel()
data = re.get_case_by_case_name('mobile_tel_segment_normalTel')
print(data)
import unittest
import requests
from demoauto.common.sendrequest import SendRequest
from demoauto.common.readexcel import ReadExcel
class TestMobileTelSegment(unittest.TestCase):
def getResult(self, case_name):
#从Excel中读取数据,需要传入casename,才指定要获取哪条用例
#返回的是一个list
caseinfo = ReadExcel().get_case_by_case_name(case_name)
url = "https://tcc.taobao.com" + caseinfo[3]
method = caseinfo[5]
params = caseinfo[4]
# 发送请求
res = SendRequest().send_request(url, method, params)
#返回实际结果和预期结果
return res, caseinfo[6]
def test01case(self):
#断言
res, expect_result = self.getResult("mobile_tel_segment_normalTel")
self.assertTrue(res.replace("\n",""), expect_result.replace("\n",""))
def test02case(self):
# 断言
res, expect_result = self.getResult("mobile_tel_segment_lessLengthTel")
self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))
def test03case(self):
# 断言
res, expect_result = self.getResult("mobile_tel_segment_moreLengthTel")
self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))
def test04case(self):
# 断言
res, expect_result = self.getResult("mobile_tel_segment_characterException")
self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(TestMobileTelSegment("test01case"))
suite.addTest(TestMobileTelSegment("test02case"))
suite.addTest(TestMobileTelSegment("test03case"))
suite.addTest(TestMobileTelSegment("test04case"))
runner = unittest.TextTestRunner(verbosity=3)
runner.run(suite)
运行结果
小结:
1、操作excel需要使用到python的openpyxl模块
程序中有一些不经常变动的数据,比如系统的baseurl,端口号,用户名,密码,数据库连接使用到的一些数据,可以抽离出来放在配置文件中,或者登录接口返回的Token会在后续接口中使用,也可以存储在配置文件中,会使代码更干净整洁
import os
import configparser
#获取当前路径的上层路径:到demoauto
path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
#获取config文件的路径
config_path = os.path.join(path, 'cfg\config.ini')
print(config_path)
#调用读取配置文件的方法
config = configparser.ConfigParser()
config.read(config_path, encoding='utf-8')
class ReadConfig():
def get_baseInfo(self):
protocol = config.get('HTTP', 'scheme')
baseurl = config.get('HTTP', 'baseurl')
port = config.get('HTTP', 'port')
return protocol+'://'+baseurl+':'+port
#测试
if __name__ == '__main__':
data = ReadConfig().get_baseInfo()
print(data)
import unittest
import requests
from demoauto.common.sendrequest import SendRequest
from demoauto.common.readexcel import ReadExcel
from demoauto.common.readconfig import ReadConfig
class TestMobileTelSegment(unittest.TestCase):
def getResult(self, case_name):
#从配置文件读取baseurl
baseurl = ReadConfig().get_baseInfo()
#从Excel中读取数据,需要传入casename,才指定要获取哪条用例
#返回的是一个list
caseinfo = ReadExcel().get_case_by_case_name(case_name)
url = baseurl + caseinfo[3]
method = caseinfo[5]
params = caseinfo[4]
# 发送请求
res = SendRequest().send_request(url, method, params)
#返回实际结果和预期结果
return res, caseinfo[6]
def test01case(self):
#断言
res, expect_result = self.getResult("mobile_tel_segment_normalTel")
self.assertTrue(res.replace("\n",""), expect_result.replace("\n",""))
def test02case(self):
# 断言
res, expect_result = self.getResult("mobile_tel_segment_lessLengthTel")
self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))
def test03case(self):
# 断言
res, expect_result = self.getResult("mobile_tel_segment_moreLengthTel")
self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))
def test04case(self):
# 断言
res, expect_result = self.getResult("mobile_tel_segment_characterException")
self.assertTrue(res.replace("\n", ""), expect_result.replace("\n", ""))
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(TestMobileTelSegment("test01case"))
suite.addTest(TestMobileTelSegment("test02case"))
suite.addTest(TestMobileTelSegment("test03case"))
suite.addTest(TestMobileTelSegment("test04case"))
runner = unittest.TextTestRunner(verbosity=3)
runner.run(suite)
小结:
1、读写配置文件需要引入configparser模块
1、生成测试报告的py文件,我在网上找了个大神写的靠谱的模版
https://github.com/findyou/HTMLTestRunnerCN/tree/dev
这里选的是中文版本的报告,复制下来放在createreport.py中
demoauto目录下创建执行所有case的类,把刚才test_mobile_tel_segment.py中的main方法放过来
import unittest
from demoauto.cases.test_mobile_tel_segment import TestMobileTelSegment
from demoauto.common.createreport import HTMLTestReportCN
import os
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(TestMobileTelSegment("test01case"))
suite.addTest(TestMobileTelSegment("test02case"))
suite.addTest(TestMobileTelSegment("test03case"))
suite.addTest(TestMobileTelSegment("test04case"))
# runner = unittest.TextTestRunner(verbosity=3)
# runner.run(suite)
# 获取当前路径:到demoauto
path = os.path.abspath(os.path.dirname(__file__))
filePath = os.path.join(path, 'result\\Report.html')
fp = open(filePath, 'wb')
#需要传入Report的路径
runner = HTMLTestReportCN(
stream=fp,
title='{ AutoTest Report }',
# description='',
# tester="Findyou"
)
runner.run(suite)
这里发现一个问题,test_mobile_tel_segment.py文件中断言assertTrue写得有问题,结果与预期值等时都会返回通过,因为assertTrue的参数是一个表达式,所以更正为如下:
def test01case(self):
#断言
res, expect_result = self.getResult("mobile_tel_segment_normalTel")
self.assertTrue(res.replace("\n","")== expect_result.replace("\n",""))
print(res)
print(expect_result)
def test02case(self):
# 断言
res, expect_result = self.getResult("mobile_tel_segment_lessLengthTel")
self.assertTrue(res.replace("\n", "")==expect_result.replace("\n", ""))
print(res)
print(expect_result)
def test03case(self):
# 断言
res, expect_result = self.getResult("mobile_tel_segment_moreLengthTel")
self.assertTrue(res.replace("\n", "")==expect_result.replace("\n", ""))
def test04case(self):
# 断言
res, expect_result = self.getResult("mobile_tel_segment_characterException")
self.assertTrue(res.replace("\n", "")==expect_result.replace("\n", ""))
运行runallcase.py,Report.html生成代码,浏览器打开该文件。最后测试结果:
页面会显示test_mobile_tel_segment中print的内容
import smtplib
from email.header import Header
from email.mime.text import MIMEText
from email.mime.multipart import MIMEMultipart
from email.mime.application import MIMEApplication
import os
class SendEmail():
def send_mail(self):
# 邮件服务器
smtpserver = 'smtp.163.com'
# 发件人和密码
sender = '[email protected]'
password = 'xxxxxxxx'
# password = 'xxxxxxxxx'
# 接收人
receiver = '[email protected]'
# 邮件主题
subject = u'自动化测试报告'
# 获取当前路径的上层路径:到demoauto
path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
# 获取config文件的路径
file_path = os.path.join(path, 'result\\Report.html')
print(file_path)
# ----------------------------------------------------------
# 连接登录邮箱
server = smtplib.SMTP(smtpserver, 25)
server.login(sender, password)
# ----------------------------------------------------------
# 构建邮件附件
msg = MIMEMultipart()
part_attach1 = MIMEApplication(open(file_path, 'rb').read()) # 打开附件
part_attach1['Content-Type'] = 'application/octet-stream'
part_attach1.add_header('Content-Disposition', 'attachment', filename=file_path) # 为附件命名
msg.attach(part_attach1)
text = MIMEText("哈哈哈,我给你发送邮件啦","plain",'utf-8')
msg['From'] = sender
msg['To'] = receiver
msg['Subject'] = Header(subject, 'utf-8').encode()
msg.attach(text)
# ----------------------------------------------------------
# 发送邮件
server.sendmail(sender, [receiver], msg.as_string())
server.quit()
print("发送成功!")
# if __name__ == '__main__':
# send_mail()
修改runallcase.py
import unittest
from demoauto.cases.test_mobile_tel_segment import TestMobileTelSegment
from demoauto.common.createreport import HTMLTestReportCN
import os
from demoauto.common.sendmail import SendEmail
if __name__ == '__main__':
suite = unittest.TestSuite()
suite.addTest(TestMobileTelSegment("test01case"))
suite.addTest(TestMobileTelSegment("test02case"))
suite.addTest(TestMobileTelSegment("test03case"))
suite.addTest(TestMobileTelSegment("test04case"))
# runner = unittest.TextTestRunner(verbosity=3)
# runner.run(suite)
# 获取当前路径:到demoauto
path = os.path.abspath(os.path.dirname(__file__))
filePath = os.path.join(path, 'result\\Report.html')
fp = open(filePath, 'wb')
#需要传入Report的路径
runner = HTMLTestReportCN(
stream=fp,
title='{ AutoTest Report }',
# description='',
# tester="Findyou"
)
runner.run(suite)
SendEmail().send_mail()
小结:
1、可能会遇到SMTPAuthenticationError: (550, b’User has no permission’)
或smtplib.SMTPAuthenticationError: (535, b’Error: authentication failed’),解决方法如下:
1、开启授权:
https://help.mail.163.com/faqDetail.do?code=d7a5dc8471cd0c0e8b4b8f4f8e49998b374173cfe9171305fa1ce630d7f67ac2cda80145a1742516
2、代码里把邮箱的password设置为这个授权码
搭建这个框架用了一个多星期,不熟悉python的一些语法,靠百度搭建起来了。遇到了很多问题,一步步解决了,也算有所收获。其中还有很多改进的地方。后面有耐心再改吧。
1、邮箱的信息从配置文件中读取
2、测试用例封装成类
完整代码上传到csdn,需要修改一下自己的邮箱