美文网首页软件测试
PYTHON接口自动化框架

PYTHON接口自动化框架

作者: A丶咔咔 | 来源:发表于2020-06-24 17:31 被阅读0次

项目背景

公司内部的软件采用B/S架构,管理实验室数据,实现数据的存储和分析统计。大部分是数据的增删改查,由于还在开发阶段,所以UI界面的变化非常快,之前尝试过用python+selenium进行UI自动化测试,后来发现今天刚写好的脚本第二天前端就改了页面,又得重新去定位元素什么的,消耗大量的精力与时间维护自动化脚本。针对此种情况,对接口测试较为有效。

工具

由于开发那里不能提供后台代码给我,只能通过抓包分析。使用fiddler抓包,发现前端与后台都是采用POST方法交互,前端POST数据,后台返回数据。这样也比较简单粗暴,直接针对每个接口POST测试数据,然后观察返回值就好了。

使用excel编写测试用例和数据,requests发送HTTP请求。

功能模块

通过xlrd库读取excel中的测试用例和数据

requests负责发送数据并接收后台返回的数据

针对测试结果,需要保存测试日志并生成测试报告,采用python自带的logging记录日志,测试报告采用html格式。

同时测试完成后,需要将测试报告发送给相关的开发人员,需要有自动发送邮件的功能

目录结构

 代码实现

#通过自带的ConfigParser模块,读取邮件发送的配置文件,作为字典返回

import ConfigParser

def get_conf():

    conf_file = ConfigParser.ConfigParser()

    conf_file.read(os.path.join(os.getcwd(),'conf.ini'))

    conf = {}

    conf['sender'] = conf_file.get("email","sender")

    conf['receiver'] = conf_file.get("email","receiver")

    conf['smtpserver'] = conf_file.get("email","smtpserver")

    conf['username'] = conf_file.get("email","username")

    conf['password'] = conf_file.get("email","password")

    returnconf

配置文件格式

 这个logging不熟悉的可以google一下,还是挺有用的,需要自己配置一下。需要手动新建一个空白的.log文件。

#此处使用python自带的logging模块,用来作为测试日志,记录测试中系统产生的信息。

import logging,os

log_file = os.path.join(os.getcwd(),'log/sas.log')

log_format ='[%(asctime)s] [%(levelname)s] %(message)s'    #配置log格式

logging.basicConfig(format=log_format, filename=log_file, filemode='w', level=logging.DEBUG)

console = logging.StreamHandler()

console.setLevel(logging.DEBUG)

formatter = logging.Formatter(log_format)

console.setFormatter(formatter)

logging.getLogger('').addHandler(console)

excel文件如下图

python读取excel跟读取一个二维数组差不多,下标也是从0开始

#读取testcase excel文件,获取测试数据,调用interfaceTest方法,将结果保存至errorCase列表中。

import xlrd,hashlib,json

def runTest(testCaseFile):

      testCaseFile = os.path.join(os.getcwd(),testCaseFile)

      if not os.path.exists(testCaseFile):

          logging.error('测试用例文件不存在!')

          sys.exit()

      testCase = xlrd.open_workbook(testCaseFile)

      table = testCase.sheet_by_index(0)

      errorCase = []                #用于保存接口返回的内容和HTTP状态码

      s = None

      foriinrange(1,table.nrows):

            iftable.cell(i,9).vale.replace('\n','').replace('\r','') !='Yes':

                continue            num = str(int(table.cell(i,0).value)).replace('\n','').replace('\r','')

            api_purpose = table.cell(i,1).value.replace('\n','').replace('\r','')

            api_host = table.cell(i,2).value.replace('\n','').replace('\r','')

            request_method = table.cell(i,4).value.replace('\n','').replace('\r','')

            request_data_type = table.cell(i,5).value.replace('\n','').replace('\r','')

            request_data = table.cell(i,6).value.replace('\n','').replace('\r','')

            encryption = table.cell(i,7).value.replace('\n','').replace('\r','')

            check_point = table.cell(i,8).value

            ifencryption =='MD5':              #如果数据采用md5加密,便先将数据加密

                request_data = json.loads(request_data)

                request_data['pwd'] = md5Encode(request_data['pwd'])

            status, resp, s = interfaceTest(num, api_purpose, api_host, request_url, request_data, check_point, request_methon, request_data_type, s)

            ifstatus !=200or check_point notin resp:            #如果状态码不为200或者返回值中没有检查点的内容,那么证明接口产生错误,保存错误信息。

                errorCase.append((num +''+ api_purpose, str(status),'http://'+api_host+request_url, resp))

        returnerrorCase

下面的就是接口部分

由于所有的操作必须在系统登录之后进行,一开始没有注意到cookie这一点,每读取一个测试用例,都会新建一个session,导致无法维护上一次请求的cookie。然后将cookie添加入请求头中,但是第二个用例仍然无法执行成功。后来用fiddler抓包分析了一下,发现cookie的值竟然是每一次操作后都会变化的!!!

所以只能通过session自动维护cookie。

在interfaceTest函数中,返回三个值,分别是HTTP CODE,HTTP返回值与session。再将上一次请求的session作为入参传入interfaceTest函数中,在函数内部判断session是否存在,如果不为None,那么直接利用传入的session执行下一个用例,如果为None,那么新建一个session。

#接受runTest的传参,利用requests构造HTTP请求

import requests

def interfaceTest(num, api_purpose, api_host, request_method,

                  request_data_type, request_data, check_point, s=None)

    headers = {'Content-Type':'application/x-www-form-urlencoded; charset=UTF-8',

                      'X-Requested-With':'XMLHttpRequest',

                      'Connection':'keep-alive',

                      'Referer':'http://'+ api_host,

                      'User-Agent':'Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/49.0.2623.110 Safari/537.36'                }

    ifs == None:

          s = requests.session()

    ifrequest_method =='POST':

          ifrequest_url !='/login' :

              r = s.post(url='http://'+api_host+request_url, data = json.loads(request_data), headers = headers)        #由于此处数据没有经过加密,所以需要把Json格式字符串解码转换成**Python对象**          elif request_url =='/login' :

              s = requests.session()

              r = s.post(url='http://'+api_host+request_url, data = request_data, headers = headers)          #由于登录密码不能明文传输,采用MD5加密,在之前的代码中已经进行过json.loads()转换,所以此处不需要解码

    else:

          logging.error(num +''+ api_purpose +'  HTTP请求方法错误,请确认[Request Method]字段是否正确!!!')

          s = None

          return400, resp, s

    status = r.status_code

    resp = r.text

    print resp

    ifstatus ==200 :

        if re.search(check_point, str(r.text)):

            logging.info(num +''+ api_purpose +' 成功,'+ str(status) +', '+ str(r.text))

            return status, resp, s

        else:

            logging.error(num +''+ api_purpose +' 失败!!!,['+ str(status) +'], '+ str(r.text))

            return200, resp , None

    else:

            logging.error(num +''+ api_purpose +'  失败!!!,['+ str(status) +'],'+ str(r.text))

            returnstatus, resp.decode('utf-8'), None

import hashlib

def md5Encode(data):

      hashobj = hashlib.md5()

      hashobj.update(data.encode('utf-8'))

      return hashobj.hexdigest()

def sendMail(text):

      mail_info = get_conf()

      sender = mail_info['sender']

      receiver = mail_info['receiver']

      subject ='[AutomationTest]接口自动化测试报告通知'      smtpserver = mail_info['smtpserver']

      username = mail_info['username']

      password = mail_info['password']

      msg = MIMEText(text,'html','utf-8')

      msg['Subject'] = subject

      msg['From'] = sender

      msg['To'] =''.join(receiver)

      smtp = smtplib.SMTP()

      smtp.connect(smtpserver)

      smtp.login(username, password)

      smtp.sendmail(sender, receiver, msg.as_string())

      smtp.quit()

def main():

      errorTest = runTest('TestCase/TestCase.xlsx')

      iflen(errorTest) >0:

          html ='<html><body>接口自动化扫描,共有 '+ str(len(errorTest)) +' 个异常接口,列表如下:'+'</p><table><tr><th style="width:100px;text-align:left">接口</th><th style="width:50px;text-align:left">状态</th><th style="width:200px;text-align:left">接口地址</th><th  style="text-align:left">接口返回值</th></tr>'fortestin errorTest:

              html = html +'<tr><td style="text-align:left">'+ test[0] +'</td><td style="text-align:left">'+ test[1] +'</td><td style="text-align:left">'+ test[2] +'</td><td style="text-align:left">'+ test[3] +'</td></tr>'              sendMail(html)if__name__ =='__main__':

    main()

以上就是一个简单的接口测试实现,参考了论坛里的大神们很多东西,还有很多不足之处。例如html格式的邮件很简陋,可以考虑生成一个HTML的测试报告,作为附件发送。

接口方法只实现了一个POST。

笔者这边创建了一个软件测试技术交流群1125760266,欢迎大家加入,共同探讨学习!

相关文章

网友评论

    本文标题:PYTHON接口自动化框架

    本文链接:https://www.haomeiwen.com/subject/tofdfktx.html