python自動化測試—配置文件的使用


一、什么是配置文件?

  • 配置文件示例  

[mysql]
default-character-set = utf8

[mysqld]
port = 3306
basedir = c:\mysql-5.7.25-winx64\mysql-5.7.25-winx64
daradir = c:\mysql-5.7.25-winx64\mysql-5.7.25-winx64\data
max_connections = 200
character-set-server = utf8
default-storage-engine = INNODB
explicit_defaults_for_timestamp = true
  • 為什么要做配置文件?

      所有的代碼和配置都變成模塊化可配置化,這樣就提高了代碼的復用性,不用每次都去修改代碼內部。

  • 場景舉例

     1、多處地方需要使用同一個參數,這時候最好是配置化,這樣改一處就可以了

     2、如果是經常變化的變量,我們也可以做這個配置。---> 與參數化要區分開來

  • python中常見的配置文件格式

   .ini、.conf、.cfg結尾的文件

  • 配置對象

    • section
    • option

二、ConfigParser模塊

掌握一些比較基礎的用法:跟file文件一樣,要先打開才能進行讀取操作

  • 實例化ConfigParse對象:cf = configParser.ConfigParser()

  • 打開配置文件:cf.read(配置文件名稱或者地址)

  • 常用方法:

    • read(filename)  直接讀取文件內容
    • sections()  得到所有的section,並以列表的形式返回
    • options(section)  得到該section的所有option
    • items(section)  得到該section的所有鍵值對
    • get(section,option)  得到該section中option的值,返回類型為string
    • getint(section,option)  得到該section中option的值,返回為int類型,還有相應的getboolean()和getfloat()
  • 練習

import configparser
# 實例化ConfigParser對象
conf = configparser.ConfigParser()
# 打開配置文件
cf = conf.read("my.conf",encoding = 'utf8')
# 根據section和option得到option的值
a = conf.get('mysqld','port')
print(a)

# 得到所有的section,並以列表的形式返回
b = conf.sections()
print(b)
# 得到該section的所有option
c = conf.options('mysqld')
print(c)
# 得到該section所有的鍵值對
d = dict(conf.items("mysql"))
print(d)

輸出結果為:

  •  封裝一個讀取配置文件的類

import configparser
"""
為什么要封裝?
    封裝是為了使用起來更加方便,便於再次修改
封裝的需求?
    封裝成什么樣子才能達到我們的目的
封裝的原則:
    寫死的固定數據(變量),可以封裝成雷屬性
    實現某個功能的代碼封裝成方法
    在各個辦法中都要用到的數據,抽離出來作為實例屬性
"""

# 封裝前 讀取數據(三部曲)
# 實例化ConfigParser對象
# conf = configparser.ConfigParser()
# 打開配置文件
# conf.read("config.ini",encoding='utf8')
# # 根據section和option得到option的值
# conf.get('excel','file_name')

class ReadConfig(configparser.ConfigParser):

    def __init__(self):
        # 實例化對象
        super().__init__()
        # 加載文件
        self.read(r"E:\python_api_test\API_Test_v4_config\conf\config.ini",encoding='utf8')

conf = ReadConfig()
  • 在其他模塊調用封裝好的配置文件時:from xxxx.xxxx.config import conf

三、將配置文件集成到單元測試中

1、項目結構

  • common:這個目錄用來存放的是自己封裝的類
  • conf:這個目錄用來存放配置文件
  • librarys:這個目錄用來存放已封裝好的模塊(HTMLtestrunner、ddt)
  • logs:這個目錄用來存放日志文件
  • data:這個目錄用來存放excel的測試用例數據
  • reposts:這個目錄用來存放生成的的測試報告
  • testcases:這個目錄用來存放所有的測試用例模塊

2、各項目層的結構圖

3、各項目層的具體代碼

  • common層(包括config.py文件、mylogging_v3.py文件、read_excel_data.py文件)

新建config.py文件

import configparser
"""
為什么要封裝?
    封裝是為了使用起來更加方便,便於再次修改
封裝的需求?
    封裝成什么樣子才能達到我們的目的

封裝的原則:
    寫死的固定數據(變量),可以封裝成雷屬性
    實現某個功能的代碼封裝成方法
    在各個辦法中都要用到的數據,抽離出來作為實例屬性
"""

# 封裝前 讀取數據(三部曲)
# 實例化ConfigParser對象
# conf = configparser.ConfigParser()
# 打開配置文件
# conf.read("config.ini",encoding='utf8')
# # 根據section和option得到option的值
# conf.get('excel','file_name')
class ReadConfig(configparser.ConfigParser):
    def __init__(self):
        # 實例化對象
        super().__init__()
        # 加載文件
        self.read(r"E:\python_api_test\API_Test_v4_config\conf\config.ini",encoding='utf8')
conf = ReadConfig()

新建mylogging_v3.py文件

import logging
from API_Test_v4_config.common.config import conf

# 日志收集器的名稱
logger_name = conf.get('log','logger_name')
# 日志收集器的級別
level = conf.get('log','level').upper()
# 輸出到控制台的日志級別
sh_level = conf.get('log','sh_level').upper()
# 輸出到文件的日志級別
fh_level = conf.get('log','fh_level').upper()
# 日志保存的文件
log_file_path = conf.get('log','log_file_path')

class MyLogging(object):
    def create_logger(*args,**kwargs):
        # 創建自己的日志收集器
        my_log = logging.getLogger(logger_name)
        # 設置收集的日志等級,設置為DEBUG等級
        my_log.setLevel(level)
        # 日志輸出渠道
        # 創建一個日志輸出渠道(輸出到控制台),並且設置輸出的日志等級為INFO以上
        l_s = logging.StreamHandler()
        l_s.setLevel(sh_level)
        # 創構建一個日志輸出渠道(輸出到文件),並且設置輸出的日志等級為DEBUG以上
        l_f = logging.FileHandler(log_file_path,encoding='utf8')
        l_f.setLevel(fh_level)
        #將日志輸出渠道添加到日志收集器中
        my_log.addHandler(l_s)
        my_log.addHandler(l_f)
        # 設置日志輸出的格式
        ft = "%(asctime)s - [%(filename)s -->line:%(lineno)d] - %(levelname)s: %(message)s"
        ft = logging.Formatter(ft)
        # 設置控制台和日志文件輸出日志的格式
        l_s.setFormatter(ft)
        l_f.setFormatter(ft)
        return my_log

    def debug(self,msg):
        self.my_log.debug(msg)

    def info(self,msg):
        self.my_log.info(msg)

    def warning(self,msg):
        self.my_log.warning(msg)

    def error(self,msg):
        self.my_log.error(msg)

    def critical(self,msg):
        self.my_log.critical(msg)

#日志輸出
m_log = MyLogging()
# 創建日志收集器
logger = m_log.create_logger()

新建read_excel_data.py文件

import openpyxl
class Case:
    def __init__(self,arrts):
        for item in arrts:
            setattr(self,item[0],item[1])
class ReadExcel(object):
    def __init__(self,filename,sheetname):
        """
        定義需要打開的文件及表名
        :param filename:   文件名
        :param sheetname:  表名
        """
        self.wb = openpyxl.load_workbook(filename)    # 打開工作簿
        self.sheet = self.wb[sheetname]               # 選定表單
        self.filename = filename

    # 特殊的魔術方法,在對象銷毀之后執行的
    def __del__(self):
        # 關閉文件
        self.wb.close()
    def read_data_line(self):
        #按行讀取數據轉化為列表
        rows_data = list(self.sh.rows)
        # print(rows_data)
        # 獲取表單的表頭信息
        titles = []
        for title in rows_data[0]:
            titles.append(title.value)
        # print(titles)
        #定義一個空列表用來存儲測試用例
        cases = []
        for case in rows_data[1:]:
            # print(case)
            data = []
            for cell in case: #獲取一條測試用例數據
                # print(cell.value)
                data.append(cell.value)
                # print(data)
                #判斷該單元格是否為字符串,如果是字符串類型則需要使用eval();如果不是字符串類型則不需要使用eval()
                if isinstance(cell.value,str):
                    data.append(eval(cell.value))
                else:
                    data.append(cell.value)
                #將該條數據存放至cases中
            # print(dict(list(zip(titles,data))))
                case_data = dict(list(zip(titles,data)))
                cases.append(case_data)
        return cases

    def read_excel_obj_new(self,list1):
        """
        按指定的列,讀取excel中的數據,以列表的形式返回,列表中每個對象為一條測試用例,
        Excel中的表頭為對象的屬性,對應的數據為屬性值。
        :param list1: list --->要讀取的列[1,2,3...]
        :return: type:list--->[case_obj1,case_obj2.......]
        """
        # 從配置文件中讀取的數據類型為string,需要轉化為list
        list1 = eval(list1)
        # 判斷傳入的讀取數據的列數是否為空,為空的話直接讀取excel中所有的數據。
        if list1 == []:
            return self.read_data_line()
        # 獲取表里面的最大行數
        max_row = self.sheet.max_row
        # 定義一個空列表,用來存放測試用例數據
        cases = []
        # 定義一個空列表,用來存放表頭數據
        titles = []
        # 遍歷所有的行數據
        for row in range(1,max_row+1):
            case_data = []
            if row != 1:
                for column in list1:
                    info = self.sheet.cell(row,column).value
                    # print(info)
                    case_data.append(info)
                case = list(zip(titles,case_data))
                # print(case)
                case_obj = Case(case)
                cases.append(case_obj)
            else:
                for column in list1:
                    title = self.sheet.cell(row,column).value
                    titles.append(title)
                    if None in titles:
                        raise ValueError("表頭的數據有顯示為空")
        return cases
    def write_excel(self,row,column,msg):
        #寫入數據
        self.sheet.cell(row=row,column=column,value=msg)
        self.wb.save(self.filename)
  • conf層(config.ini文件--->配置文件)

新建config.ini文件

# log日志相關配置
[log]
# 日志收集器的名稱
logger_name = my_log
# 日志收集器的級別
level = DEBUG
# 輸出到控制台的日志級別
sh_level = DEBUG
# 輸出到文件的日志級別()
fh_level = debug
# 日志保存的文件
log_file_path = E:\python_api_test\API_Test_v4_config\logs\log.log

# 讀取excel中測試用例數據相關的配置
[excel]
# 用例文件名稱
file_name = E:\python_api_test\API_Test_v4_config\data\cases.xlsx
# sheet表單名稱
sheet_name = Sheet1
# 讀取表單中的列數(每條用例的數據) []空列表便是所有列
read_colums = [1,2,3]

# 測試報告相關的配置
[report]
report_path = E:\python_api_test\API_Test_v4_config\reports\report.html
report_name = python接口自動化測試報告
report_tester = 測試

 

  • data層(cases.xlsx文件--->測試用例數據)

新建cases.xlsx文件

  • testcase層(register_testcase.py文件--->注冊函數的測試用例)

新建register_testcase.py文件

import unittest
from API_Test_v4_config.register import register
from API_Test_v4_config.common.read_excel_data import ReadExcel
from ddt import ddt,data
from API_Test_v4_config.common.mylogging_v3 import logger
from API_Test_v4_config.common.config import conf

# 配置文件中讀取excel相關數據
file_name = conf.get('excel','file_name')
sheet_name = conf.get('excel','sheet_name')
read_colums = conf.get('excel','read_colums')
# 讀取excel中的數據
wb = ReadExcel(file_name,sheet_name)
cases = wb.read_excel_obj_new(read_colums)

@ddt
class RegisterTestCase(unittest.TestCase):
    def setUp(self):
        print("准備測試環境,執行測試用例之前會執行此操作")
    def tearDown(self):
        print("還原測試環境,執行完測試用例之后會執行此操作")
    @data(*cases)
    def test_register(self,case):
        self.row = case.caseid + 1
        res = register(*eval(case.data))
        try:
            self.assertEquals(eval(case.excepted),res)
        except AssertionError as e:
            res = "未通過"
            logger.error(e)
            raise e
        else:
            res = "通過"
            logger.info("該條測試用例的測試結果為:{}".format(res))
        finally:
            # 調用寫入數據的方法,在excel中回寫測試用例的執行結果
            wb.write_excel(row=self.row,column=4,msg=res)

if __name__ == '__main__':
    unittest.main()
  • 最外面層(register.py文件--->需要測試的功能函數、 register_suites.py--->執行測試套件)

新建register.py文件

# 設計用例,對注冊功能函數進行單元測試
users = [{'user': 'python18', 'password': '123456'}]
def register(username, password1, password2):
    # 注冊功能
    for user in users:  # 遍歷出所有賬號,判斷賬號是否存在
        if username == user['user']:
            # 賬號存在
            return {"code": 0, "msg": "該賬戶已存在"}
    else:
        if password1 != password2:
            # 兩次密碼不一致
            return {"code": 0, "msg": "兩次密碼不一致"}
        else:
            # 賬號不存在 密碼不重復,判斷賬號密碼長度是否在 6-18位之間
            if 6 <= len(username) <= 18 and 6 <= len(password1) <= 18:
                # 注冊賬號
                users.append({'user': username, 'password': password2})
                return {"code": 1, "msg": "注冊成功"}
            else:
                # 賬號密碼長度不對,注冊失敗
                return {"code": 0, "msg": "賬號和密碼必須在6-18位之間"}

新建register_suites.py文件

import unittest
from HTMLTestRunnerNew import HTMLTestRunner
from API_Test_v4_config.testcases import register_testcase
from API_Test_v4_config.common.config import conf

# 第二步:創建測試套件
suite = unittest.TestSuite()
# 第三步:將測試用例加載到測試套件中
loader = unittest.TestLoader()
# 通過測試用例類來添加測試用例
# suite.addTest(loader.loadTestsFromTestCase(RegisterTestCase))
# 通過模塊來添加測試用例
suite.addTest(loader.loadTestsFromModule(register_testcase))
# 添加測試用例,通過路徑加載測試用例目錄下的所有模塊
# suite.addTest(loader.discover("E:\\python_api_test\\API_Test_v4_config\\testcases"))
#第四步:執行測試套件,生成測試報告
# 讀取配置文件中report相關的配置信息
report_path = conf.get("report",'report_path')
report_name = conf.get('report','report_name')
report_tester = conf.get('report','report_tester')

with open(report_path,'wb') as f:
    runner = HTMLTestRunner(
        stream = f,
        verbosity = 2,
        title = 'python_18_report',
        description = report_name,
        tester = report_tester
    )
    runner.run(suite)

 

  

 


免責聲明!

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



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