1. 程式人生 > >基於python的接口自動化測試框架

基於python的接口自動化測試框架

urn __name__ exce 文件格式 圖片 XML pla main tex

公司內部的軟件采用B/S架構,大部分是數據的增刪改查,由於還在開發階段,所以UI界面的變化非常快,難以針對UI進行自動化測試,那樣會消耗大量的精力與時間維護自動化腳本。針對此種情況,針對接口測試較為有效。

工具選擇

針對接口測試的工具也很多,例如soup UI, robot framework ,甚至jmeter這樣的性能測試工具也可以進行接口測試。

robot framework測試框架有很多的第三方庫可以使用,采用的是填表的方式進行,較容易上手,但是無法深入底層的了解客戶端與服務器的交互過程。jmeter這樣的專註性能測試的工具,進行接口測試,有點大材小用的感覺而且無法生成測試報告。

綜上考慮,決定自己開發一個簡單的框架,優點是足夠靈活,可以隨時根據需求進行變更,後臺使用的是python flask進行開發,此次選用python 2.7.11進行框架的開發,python開發的速度很快,且容易上手,豐富的第三方庫,大大加快了開發速度和難度。

框架思路

由於是框架,所以要考慮到框架的可重用性和可維護性。采用數據驅動的設計方式,將數據分層出來,與業務邏輯剝離。這樣測試人員就可以通過數據文件專註的寫測試用例,不用關註代碼編寫,提高了效率。此次框架采用基本的excel進行數據管理。通過對excel 的讀取獲得數據。

之後將測試的結果生成HTML格式的測試報告發送給相關開發人員。

第三方庫介紹

Requests

python中有許多針對http的庫,例如自帶的urllib2,但是自帶的urllib2編寫起來實在是太費精力,所以采用號稱"HTTP for Humans"的requests庫。

xlrd

xlrd使得python可以方便的對excel文件進行讀寫操作,此次通過xlrd讀取excel文件中的測試數據。

以上第三方庫都可以通過pip直接安裝或者通過pypi下載源碼包安裝。

模塊介紹

get_conf:讀取配置文件,獲得郵件發送的配置信息,如smtpserver、receiver、sender等。

md5Encode:部分數據采用md5加密後傳輸,所以需要把從excel讀取的數據進行md5加密。

sendMail:當測試完成後,將測試報告自動的發送給相關開發人員。

runTest:此部分讀取excel中的數據,調用下方的interfaceTest方法,保存interfaceTest返回的信息。

interfaceTest:將runTest讀取的excel數據作為入參,執行接口測試,並將後臺返回的信息返回給runTest。

Excel

不知怎麽圖片一直上傳失敗,後面會將excel文件格式上傳

代碼實現

#通過自帶的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") 

    return conf
#此處使用python自帶的logging模塊,用來作為測試日誌,記錄測試中系統產生的信息。
import logging,os
log_file = os.path.join(os.getcwd(),‘log/sas.log‘)
log_format = ‘[%(asctime)s] [%(levelname)s] %(message)s‘
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)
#讀取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
      for i in range(1,table.nrows):
            if table.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

            if encryption == ‘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)
            if status != 200 or check_point not in resp:            #如果狀態碼不為200或者返回值中沒有檢查點的內容,那麽證明接口產生錯誤,保存錯誤信息。
                errorCase.append((num + ‘ ‘ + api_purpose, str(status), ‘http://‘+api_host+request_url, resp))
        return errorCase
#接受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‘
                }

     if s == None:
          s = requests.session()
     if request_method == ‘POST‘:
          if request_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
          return 400, resp, s
     status = r.status_code
     resp = r.text
     print resp
     if status == 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))
            return 200, resp , None
        else:
            logging.error(num + ‘ ‘ + api_purpose + ‘  失敗!!!,[‘ + str(status) + ‘],‘ + str(r.text))
            return status, 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‘)
      if len(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>‘
          for test in 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()

由於所有的操作必須在系統登錄之後進行,一開始沒有註意到cookie這一點,每讀取一個測試用例,都會新建一個session,導致無法維護上一次請求的cookie。然後將cookie添加入請求頭中,但是第二個用例仍然無法執行成功。後來用fiddler抓包分析了一下,發現cookie的值竟然是 每一次操作後都會變化的!!!

所以只能通過session自動維護cookie。在interfaceTest函數中,返回三個值,分別是HTTP CODE,HTTP返回值與session。再將上一次請求的session作為入參傳入interfaceTest函數中,在函數內部判斷session是否存在,如果不為None,那麽直接利用傳入的session執行下一個用例,如果為None,那麽新建一個session。

不足之處

  • 框架十分簡陋,只是簡單想法的實現,對於編碼的細節沒有完善。
  • HTML的測試報告書寫起來比較麻煩,可以考慮引入第三方庫進行HTML測試報告的書寫,將生成的HTML文件作為附件發送。
  • 只是針對公司內部的軟件,換用其他平臺就不適用,需要修改源碼。
  • 轉載:轉載:http://www.zuimoban.com/jiaocheng/python/7375.html

基於python的接口自動化測試框架