unittest接口自動化測試


我又來了,來分享年前的unittest接口自動化實戰啦。這次自動化接口框架比較簡單,但是五臟俱全。(注:項目是針對我們公司內部系統的測試,我就不分享鏈接了。)

項目簡介

項目名稱:****名片系統

項目目的:實現系統項目自動化測試執行

項目版本:v1.0

項目目錄

tools  #存放輔助方法
   configEmail.py   #發送測試報告電子郵件
  HTMLTestRunner.py #第三方插件
  log.py #輸出日志文件
  mail_receiver.txt #存放接收人郵箱地址
  read_json.py #讀取單一測試數據json文件
  read_more_json #讀取more測試數據json文件
report #存放html測試報告
logs  #存放輸入日志文件
data  #存放參數化測試數據(json文件)
case  #存放測試用例
api   #存放封裝測試方法

caselist.txt    #存放要執行的測試用例

getpathInfo.py    #獲取當前路徑

runAll.py    #運行caselist.txt中的測試用例,輸出測試報告 

項目框架

unittest單元測試框架

項目設計

1.每一個用例組合在一個測試類里面生成一個py文件

2.一個模塊(被測項目功能)對應一個py文件及一個測試類(測試文件)

3.通過 parameterized 對參數進行參數化

項目目標

1. 生成測試用例執行結果報告

2.生成測試用例執行日志

3.用例執行失敗或者執行完成后自動發送郵件報告

4.數據驅動(讀取測試數據,減少腳本維護成本)

項目代碼

  getpathInfo.py   #獲取當前路徑

import os

def get_Path():
    #獲取上級路徑
    #path = os.path.abspath(os.path.join(os.getcwd(), ".."))
    #獲取當前路徑
    path = os.path.split(os.path.realpath(__file__))[0]
    return path

if __name__ == '__main__':# 執行該文件,測試下是否OK
    print('測試路徑是否OK,路徑為:', get_Path())
getpathInfo.py

  caselist.txt  #存放可執行測試用例

  runAll.py   #運行文件

import os
import time

from BeautifulReport import BeautifulReport

import getpathInfo
import tools.HTMLTestRunner as HTMLTestRunner
import unittest
from tools.configEmail import send_email, getReceiverInfo
import tools.Log

path = getpathInfo.get_Path()
report_path = os.path.join(path, 'report')
log = tools.Log.logger

class AllTest:#定義一個類AllTest
    def __init__(self):#初始化一些參數和數據
        global resultPath
        resultPath = os.path.join(report_path)
        self.caseListFile = os.path.join(path, "caselist.txt")#配置執行哪些測試文件的配置文件路徑
        self.caseFile = os.path.join(path, "case")#真正的測試斷言文件路徑
        self.caseList = []
        log.info('resultPath'+resultPath)#將resultPath的值輸入到日志,方便定位查看問題
        log.info('caseListFile'+self.caseListFile)#同理
        log.info('caseList'+str(self.caseList))#同理

    def set_case_list(self):
        """
        讀取caselist.txt文件中的用例名稱,並添加到caselist元素組
        :return:
        """
        fb = open(self.caseListFile)
        for value in fb.readlines():
            data = str(value)
            if data != '' and not data.startswith("#"):# 如果data非空且不以#開頭
                self.caseList.append(data.replace("\n", ""))#讀取每行數據會將換行轉換為\n,去掉每行數據中的\n
        fb.close()

    def set_case_suite(self):
        """
        :return:
        """
        self.set_case_list()#通過set_case_list()拿到caselist元素組
        test_suite = unittest.TestSuite()
        suite_module = []
        for case in self.caseList:#從caselist元素組中循環取出case
            case_name = case.split("/")[-1]#通過split函數來將aaa/bbb分割字符串,-1取后面,0取前面
            print(case_name+".py")#打印出取出來的名稱
            #批量加載用例,第一個參數為用例存放路徑,第一個參數為路徑文件名
            discover = unittest.defaultTestLoader.discover(self.caseFile, pattern=case_name + '.py', top_level_dir=None)
            suite_module.append(discover)#將discover存入suite_module元素組
            print('suite_module:'+str(suite_module))
        if len(suite_module) > 0:#判斷suite_module元素組是否存在元素
            for suite in suite_module:#如果存在,循環取出元素組內容,命名為suite
                for test_name in suite:#從discover中取出test_name,使用addTest添加到測試集
                    test_suite.addTest(test_name)
        else:
            print('else:')
            return None
        return test_suite#返回測試集

    def run(self):
        """
        run test
        :return:
        """
        try:
            suit = self.set_case_suite()#調用set_case_suite獲取test_suite
            print('try')
            print(str(suit))
            if suit is not None:#判斷test_suite是否為空
                print('if-suit')
                currTime = time.strftime('%Y-%m-%d %H_%M_%S')
                filename = currTime + '.html'
                # currTime = time.strftime('%Y-%m-%d %H_%M_%S')
                # fileName = report_path + r'\report'+ currTime + '.html'
                result = BeautifulReport(suit)
                result.report(filename= filename, description='接口測試報告')
                # fp = open(fileName, 'wb')
                # runner = HTMLTestRunner.HTMLTestReportCN \
                #     (stream=fp, title='自動化接口測試報告',
                #         description='處理器:Intel(R) Core(TM) '
                #                     'i5-5200U CPU @ 2.20GHz 2.20 GHz '
                #                     '內存:8G 系統類型: 64位 版本: windows 10 專業版')
                # runner.run(suit)
            else:
                print("Have no case to test.")
        except Exception as ex:
            print(str(ex))
            #log.info(str(ex))

        finally:
            print("*********TEST END*********")
            #log.info("*********TEST END*********")
            #fp.close()
        #發送測試郵件
        # read_msg = getReceiverInfo(
        #     r'F:\python_test\Automation_interfaceTest\tools\mail_receiver.txt')
        # sendmail = send_email(read_msg)
        # sendmail.sendEmail(fileName)
# pythoncom.CoInitialize()
# scheduler = BlockingScheduler()
# scheduler.add_job(AllTest().run, 'cron', day_of_week='1-5', hour=14, minute=59)
# scheduler.start()

if __name__ == '__main__':
    AllTest().run()
runall.py

  tools   #輔助方法

  configEmail.py  # 發送郵件

import os
import smtplib


import getpathInfo
from tools.Log import Logger
from email.mime.text import MIMEText
from email.header import Header
log = Logger(__name__)
path = getpathInfo.get_Path()
report_path = os.path.join(path, 'report')  # 存放測試報告文件的路徑
mail_path = os.path.join(path,'tools')#存放收件人地址文件路徑
class send_email():
    '''
        郵件配置信息
        '''

    def __init__(self,
                 receiver,
                 subject='*******',
                 server='smtp.qq.com',
                 fromuser='******',
                 frompassword='yjkxwfmrbumrbbce',
                 sender='*******'):
        """
        :param receiver:
        :param subject:
        :param server:
        :param fromuser:
        :param frompassword:
        :param sender:
        """

        self._server = server
        self._fromuser = fromuser
        self._frompassword = frompassword
        self._sender = sender
        self._receiver = receiver
        self._subject = subject

    def sendEmail(self, fileName):
        """
        :param filename:
        :return:
        """
        #   打開報告文件讀取文件內容
        try:
            f = open(os.path.join(report_path, fileName), 'rb')
            fileMsg = f.read()
        except Exception:
            log.logger.exception(
                'open or read file [%s] failed,No such file or directory: %s' % (fileName, report_path))
            log.logger.info('open and read file [%s] successed!' % fileName)
        else:
            f.close()
            #   郵件主題
            subject = 'Python test report'  #
            #   郵件設置
            msg = MIMEText(fileMsg, 'html', 'utf-8')
            msg['subject'] = Header(subject, 'utf-8')
            msg['from'] = self._sender
            #   連接服務器,登錄服務器,發送郵件
            try:
                smtp = smtplib.SMTP()
                smtp.connect(self._server)
                smtp.login(self._fromuser, self._frompassword)
            except Exception:
                log.logger.exception('connect [%s] server failed or username and password incorrect!' % smtp)
            else:
                log.logger.info('email server [%s] login success!' % smtp)
                try:
                    smtp.sendmail(self._sender, self._receiver, msg.as_string())
                except Exception:
                    log.logger.exception('send email failed!')
                else:
                    log.logger.info('send email successed!')


#   從文件中讀取郵件接收人信息
def getReceiverInfo(fileName):
    '''
    :param filename: 讀取接收郵件人信息
    :return: 接收郵件人信息
    '''
    try:
        openFile = open(os.path.join(mail_path, fileName))
    except Exception:
        log.logger.exception('open or read file [%s] failed,No such file or directory: %s' % (fileName, mail_path))
    else:
        log.logger.info('open file [%s] successed!' % fileName)
        for line in openFile:
            msg = [i.strip() for i in line.split(',')]
            log.logger.info('reading [%s] and got receiver value is [%s]' % (fileName, msg))
            return msg


if __name__ == '__main__':# 運營此文件來驗證寫的send_email是否正確
    readMsg = getReceiverInfo('mail_receiver.txt')
    sendmail = send_email(readMsg)
    sendmail.sendEmail('report.html')
configEmail.py
HTMLTestRunner.py #第三方插件
log.py #輸出日志文件
import os
import logging
import time
from logging.handlers import TimedRotatingFileHandler
import getpathInfo

path = getpathInfo.get_Path()
log_path = os.path.join(path, 'logs')  # 存放log文件的路徑

class Logger(object):
    def __init__(self, logger_name='logs…'):
        self.logger = logging.getLogger(logger_name)
        logging.root.setLevel(logging.NOTSET)
        currTime = time.strftime("%Y-%m-%d")
        self.log_file_name = currTime+'logs'  # 日志文件的名稱
        self.backup_count = 5  # 最多存放日志的數量
        # 日志輸出級別
        self.console_output_level = 'WARNING'
        self.file_output_level = 'DEBUG'
        # 日志輸出格式
        self.formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')

    def get_logger(self):
        """在logger中添加日志句柄並返回,如果logger已有句柄,則直接返回"""
        if not self.logger.handlers:  # 避免重復日志
            console_handler = logging.StreamHandler()
            console_handler.setFormatter(self.formatter)
            console_handler.setLevel(self.console_output_level)
            self.logger.addHandler(console_handler)

            # 每天重新創建一個日志文件,最多保留backup_count份
            file_handler = TimedRotatingFileHandler(filename=os.path.join(log_path, self.log_file_name), when='D',
                                                    interval=1, backupCount=self.backup_count, delay=True,
                                                    encoding='utf-8')
            file_handler.setFormatter(self.formatter)
            file_handler.setLevel(self.file_output_level)
            self.logger.addHandler(file_handler)
        return self.logger


logger = Logger().get_logger()
log.py

 mail_receiver.txt  #存放接受人郵箱地址

 read_json.py   # 讀取單一測試數據 

import json
import getpathInfo

import os


class ReadJson(object):
    def __init__(self,filename):
        path = getpathInfo.get_Path()
        self.filepath = os.path.join(path, 'data')+"/"+filename

    def read_json(self):
         with open(self.filepath, "r", encoding="utf-8")as f:
            # 調用load方法加載文件流
            return json.load(f)

if __name__ == '__main__':
    data = ReadJson("updateuserpwd.json").read_json()
    arrs = []
    arrs.append((data.get("url"),
                data.get("userId"),
                data.get("data"),
                data.get("success"),
                data.get("message")))
    print(arrs)
read_json.py

 read_more_json.py   # 讀取more測試數據 

import json


class ReadJson(object):
    def __init__(self,filename):
        self.filepath = '../data/' +filename

    def read_json(self):
         with open(self.filepath, "r", encoding="utf-8")as f:
            # 調用load方法加載文件流
            return json.load(f)

if __name__ == '__main__':
    datas = ReadJson("login_more.json").read_json()
    arrs = []
    for data in datas.values():
        arrs.append((data.get("url"),
                data.get("mobile"),
                data.get("code"),
                data.get("expect_result"),
                data.get("status_code")))
    print(arrs)
read_more_json.py

 #測試用例

import requests

class ApiLogin(object):

    def api_post_login(self,data):
        #headers定義
        headers = {"Content-Type": "application/x-www-form-urlencoded"}
        #url定義
        url = "http://*******"
        #調用post返回相應對象
        return requests.post(url, headers=headers,data = data)
api_login.py
#客戶經理登錄接口
import sys
import unittest
from api.api_login import ApiLogin
from parameterized import parameterized
from tools.read_more_json  import ReadJson
import tools.Log

log = tools.Log.logger

#讀取數據函數
def get_data():
    datas = ReadJson('login.json').read_json()
    arrs = []
    for data in datas.values():
        arrs.append((data.get("data"),
                     data.get("message"),
                     data.get("desc")))
    return arrs

class TestLogin(unittest.TestCase):
    '''登錄接口 '''
    @parameterized.expand(get_data())  # 參數化測試用例
    def test_login(self,data,message,desc):
        #調用登錄方法
        s = ApiLogin().api_post_login(data)
        #調試使用添加描述
        self._testMethodDoc = desc
        #print('查看響應結果:',s.text)
        #斷言響應信息
        self.assertIn(message,s.text)
        # 生成響應日志
        log.info('[%s]響應數據為:[%s]' % (sys._getframe().f_code.co_name, s.text))

if __name__ == '__main__':
    unittest.main()
test_login.py

#測試數據

{
   "login_001":{
               "data":{"loginName":"admin", "password": "123456","memberPass": "on"},
               "message": "名片管理系統",
               "desc": "正常登錄"},
   "login_002": {
               "data":{"loginName":"admin", "password": "123456n","memberPass": "on"},
               "message": "密碼不正確",
               "desc": "賬號錯誤登錄"},
   "login_003": {
               "data":{"loginName":"admir", "password": "123456","memberPass": "on"},
               "message": "賬號不存在",
               "desc": "密碼錯誤登錄"},
   "login_004": {
               "data":{"loginName":" ", "password": "123456","memberPass": "on"},
               "message": "帳號密碼登錄",
               "desc": "密碼為空登錄"},
   "login_005": {
               "data":{"loginName":"admin", "password": " ","memberPass": "on"},
               "message": "密碼不正確",
               "desc":"賬號為空登錄"},
   "login_006": {
               "data":{"loginName":"adm in", "password": "123456","memberPass": "on"},
               "message": "賬號不存在",
               "desc":"賬號存在空格登錄"},
   "login_007": {
               "data":{"loginName":"admin", "password": "123 456","memberPass": "on"},
               "message": "密碼不正確",
               "desc":"密碼存在空格登錄"},
   "login_008": {
               "data":{"loginName":"admin.", "password": "123456","memberPass": "on"},
               "message": "賬號不存在",
               "desc":"賬號存在特殊符號登錄"},
   "login_009": {
               "data":{"loginName":"admin", "password": "123456.","memberPass": "on"},
               "message": "密碼不正確",
               "desc":"密碼存在特殊符號登錄"},
   "login_010": {
               "data":{"loginName":"admi", "password": "123456","memberPass": "on"},
               "message": "賬號不存在",
               "desc":"賬號不完整登錄"},
   "login_010": {
               "data":{"loginName":"admin", "password": "12345","memberPass": "on"},
               "message": "密碼不正確",
               "desc":"密碼不完整登錄"}
}
test_login_data.json

 #測試報告

 

 就這樣吧,其他測試用例與之類似就不展出了。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM