python自動化測試之異常及日志


  為了保持自動化測試用例的健壯性,異常的捕獲及處理,日志的記錄對掌握自動化測試執行情況尤為重要,這里便詳細的介紹下在自動化測試中使用到的異常及日志,並介紹其詳細的用法。

  一、日志

    打印日志是很多程序的重要需求,良好的日志輸出可以幫我們更方便的檢測程序運行狀態。Python標准庫提供了logging模塊,切記Logger從來不直接實例化,其好處不言而喻,接下來慢慢講解Logging模塊提供了兩種記錄日志的方式。 

  1. logging之模塊級別的函數方式記錄日志
    import logging #設置日志,包括filename、level、format、filemode、stream,其中format屬性極其豐富,詳情可查看API文檔,這里只做簡要介紹
    logging.basicConfig(level = logging.INFO,
      format = '%(asctime)s - %(name)s - %(levelname)s - %(message)s',
      datefmt = "%Y/%m%d %H%M%S",
      filename = "log.txt") #消息級別,五級 logging.debug("芹澤多摩雄") logging.info("") logging.warning("") logging.error("") logging.critical("")

     

  2.   logging之日志系統的四大組件(日志器、處理器、過濾器、格式器)方式記錄日志

    import logging
    # 生成日志實例,日志器
    logger = logging.getLogger(__name__)
    #基本單元的配置(LEVER)
    logger.setLevel(level = logging.INFO)
    formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
    
    #生成管道分支,處理器
    handler_1 = logging.FileHandler("log.txt")
    handler_2 = logging.StreamHandler()
    
    #自定義格式,格式器
    handler_1.setFormater(formatter, “%Y-%m-%d %H:%M:%S”)
    handler_2.setFormater(formatter, “%Y-%m-%d %H:%M:%S”)
    
    #對接分支管道與源頭,處理器
    logger.addHandler(handler_1)
    logger.addHandler(handler_2)
    
    #層級結構,logger的名稱是一個以'.'分割的層級結構,每個'.'后面的logger都是'.'前面的logger的children,通常配合過濾器一起使用
    #過濾器
    。。。。保留
    
    #開始記錄
    logger.debug("芹澤多摩雄") 
    logger.info("")
    logger.warning("")
    logger.error("")
    logger.critical("")

     

     

     

     

  3. 細心的盆友又可以發現,可以發現,logging有一個日志處理的主對象,其他處理方式都是通過addHandler添加進去,這里采用logging.StreamHandler實現日志輸出到流(控制台),也可以用FileHandler實現日志輸出到文件

  4. 日志回滾
    import logging from logging.handlers import RotatingFileHandler logger = logging.getLogger(__name__) logger.setLevel(level = logging.INFO) #定義一個RotatingFileHandler,最多備份3個日志文件,每個日志文件最大1K
    rHandler = RotatingFileHandler("log.txt",maxBytes = 1*1024,backupCount = 3) rHandler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') rHandler.setFormatter(formatter) console = logging.StreamHandler() console.setLevel(logging.INFO) console.setFormatter(formatter) logger.addHandler(rHandler) logger.addHandler(console) logger.debug("芹澤多摩雄") logger.info("") logger.warning("") logger.error("") logger.critical("")
  5. 多模塊使用
    #主模塊
    import logging import subModule logger = logging.getLogger("mainModule") logger.setLevel(level = logging.INFO) handler = logging.FileHandler("log.txt") handler.setLevel(logging.INFO) formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') handler.setFormatter(formatter) console = logging.StreamHandler() console.setLevel(logging.INFO) console.setFormatter(formatter) logger.addHandler(handler) logger.addHandler(console) #子模塊
    import logging module_logger = logging.getLogger("mainModule.sub") class SubModuleClass(object): def __init__(self): self.logger = logging.getLogger("mainModule.sub.module")

    細心的盆友會再次發現其實對logger的命名很重要,首先在主模塊定義了logger'mainModule',並對它進行了配置,子模塊可以共享父logger的定義和配置,所謂的父子logger是通過命名來識別,任意以'mainModule'開頭的logger都是它的子logger,例如'mainModule.sub'

  6. 事實上,縱使有繼承配置或者自定義的配置日志功能,但實際中的大項目中還是略麻煩的,這里主要用到JSON或者yaml進行配置封裝,這樣加載該文件即可加載日志的配置,下回分解具體操作,最后來一發實例。
    # -*- coding: utf-8 -*-
    __author__ = 'Secret608'
    
    import logging import time import os import re class Log(object): def __init__(self, loggerName): ''' 進行日志初始化,包括存儲路徑、名稱、級別、調用文件等 '''
                #基本屬性
                self.logger = logging.getLogger(loggerName) self.logger.setLevel(logging.WARNING) #特有屬性(文件地址+日志記錄格式)
                rq = time.strftime('%Y%m%d_%H%M%S', time.localtime(time.time())) log_path = os.path.join(os.path.dirname(os.getcwd()), 'logs') log_title = os.path.join(log_path, loggerName + '_'+ rq) + ".log" formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s') log = logging.FileHandler(log_title) log.setFormatter(formatter) #加到基本屬性中,得到一個完整的初始化對象
     self.logger.addHandler(log) def getLog(self): return self.logger def delLog(self, fileName): log_path = os.path.join(os.path.dirname(os.getcwd()), 'logs') regexp = re.compile('^'+fileName+'s.*') filelist = os.listdir(log_path) try: [os.remove(os.path.join(log_path, i)) for i in filelist if regexp.match(i) == None] except WindowsError: pass
            else: return "ok"
    
    
    if __name__ == "__main__": a = Log("hah") a.delLog("hah")

     

 

  二、異常

    • 異常類型
      • 內置異常:Python的異常處理能力是很強大的,它有很多內置異常,可向用戶准確反饋出錯信息。在Python中,異常也是對象,可對它進行操作。BaseException是所有內置異常的基類,但用戶定義的類並不直接繼承BaseException,所有的異常類都是從Exception繼承,且都在exceptions模塊中定義。
      • 自定義異常:可以通過創建一個新的異常類擁有自己的異常,異常應該是通過直接或間接的方式繼承自Exception類。比如創建了一個MyError類,基類為Exception,用於在異常觸發時輸出更多的信息。
    • 異常捕獲
      • 發生異常時,我們就需要對異常進行捕獲,然后進行相應的處理。python的異常捕獲常用try...except...結構,把可能發生錯誤的語句放在try模塊里,用except來處理異常,每一個try,都必須至少對應一個except。此外,與python異常相關的關鍵字主要有:try/except、pass、as(定義異常實例)、else、finally、raise。
      • 捕獲所有異常:
      •  

        # -*- coding: utf-8 -*-
        
        #異常處理的語法:
        try#執行可能出現異常的語句
        except '異常名字'#出現異常執行的語句
        else#執行沒有出現異常的語句
        finally: #異常與否都執行的語句
        
        #demo
        try: a = 0 b = 1 c = b/a print(c) except ZeroDivisionError: print("分母不能為0") except NameError: print("名稱錯誤") except (ZeroDivisionError, NameError): print("你的分母等於0或者變量名不存在") except Exception as e: print("你的變量名或者分母值確實沒錯,但是出現了其他的錯誤,詳見%s" %e) d = 1   
        finally: print("聽說沒有錯誤?不能忍,反正我要讓你難受!") if d == 1: raise ValueError("你有其它錯誤") elseraise FuckError("開不開心?") #咦? FuckError是啥?貌似沒有定義啊,這里定義一波,屆時位置移動到前面去
            class FuckError(Exception): def __int__(self,*args,**keargs): super(FuckError,self).__int__(*args,**keargs)#python2
                    self.args = args print(args)   

         

      • 更多的異常可參看API(https://docs.python.org/3/library/exceptions.html#base-classes

 


免責聲明!

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



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