循序漸進的方式介紹(也可以直接到步驟4中看示例模板)
1. 簡單示例:
from selenium import webdriver import time driver = webdriver.Chrome() def get_screen(): now_time = time.strftime('%Y_%m_%d_%H_%M_%S') driver.get_screenshot_as_file(f'{now_time}.jpg') def screen(func): # 自動截圖裝飾器 def inner(*args, **kwargs): # 由於我們不知道被調用的函數到底有幾個參數,寫一個萬能裝飾器,傳可變參數 try: f = func(*args, **kwargs) # return f except: get_screen() # 失敗后截圖 # raise return inner @screen # 加裝飾 def search(driver): driver.get('http://www.baidu.com') driver.find_element_by_id('kw11').send_keys('python') # id不對,會運行失敗 driver.find_element_by_id('su').click() time.sleep(5) driver.quit() search(driver) # 執行
以上代碼,會發現driver作為全局變量存在,無法傳入裝飾器中。同時,也沒有和unittest結合。我們對此進行改良。
2. 不帶參數的裝飾器
- 被裝飾的函數,傳入__init__()
- 調用被裝飾的函數時,自動調用__call__()
__init__()里是初始化參數,__call__()里是原函數參數
class decoratorWithoutArguments(object): def __init__(self, f): # 被裝飾的函數,傳入__init__() print('inside __init__()') self.f = f def __call__(self, *args): # 調用被裝飾的函數時,自動調用__call__() print('inside __call__()') self.f(*args) print('after self.f(*args)') @decoratorWithoutArguments # 不帶參數 def say_hello(a1, a2): print('say hello arguments: ', a1, a2) say_hello(2, 3)
運行結果如下:
inside __init__()
inside __call__()
say hello arguments: 2 3
after self.f(*args)
3. 帶參數的裝飾器
- 參數寫到__init()__里
- 被裝飾的函數傳入__call()__
class decoratorWithArguments(object): def __init__(self, arg1, arg2, arg3): # 傳入裝飾器參數 print('inside __init__()') self.arg1 = arg1 self.arg2 = arg2 self.arg3 = arg3 def __call__(self, f): # 可以只給它傳一個參數 -- 被裝飾的函數 print('inside __call__()') def wrapped_f(*args): print('inside wrapped_f()') print('decorator arguments: ', self.arg1, self.arg2, self.arg3) f(*args) print('after f(*args)') return wrapped_f @decoratorWithArguments('hello', 'world', 42) # 帶參數 def say_hello(a1, a2, a3, a4): print('say_hell0 arguments: ', a1, a2, a3, a4) say_hello(1, 2, 3, 4)
運行結果如下:
inside __init__()
inside __call__()
inside wrapped_f()
decorator arguments: hello world 42
say_hell0 arguments: 1 2 3 4
after f(*args)
so,可以嘗試按此方法,將瀏覽器驅動傳入裝飾器中
4. 結合unittest
百度首頁為例,有異常時截圖,代碼如下:
from selenium import webdriver import unittest import time class Screen(object): def __init__(self, driver): self.driver = driver def __call__(self, func): def inner(*args, **kwargs): try: return func(*args, **kwargs) except: now_time = time.strftime('%Y_%m_%d_%H_%M_%S') # 異常時,截圖 self.driver.get_screenshot_as_file(f'{now_time}.png') raise # 拋出異常,不然會認為測試用例執行通過 return inner class MyTest(unittest.TestCase): driver = webdriver.Chrome() @classmethod def setUpClass(cls): cls.driver.get('http://www.baidu.com') @Screen(driver) def test_01(self): self.driver.find_element_by_id('kw').clear() self.driver.find_element_by_id('kw').send_keys('python') self.driver.find_element_by_id('su1').click() # id不對,會報錯 time.sleep(3) @Screen(driver) def test_02(self): self.driver.find_element_by_id('kw').clear() self.driver.find_element_by_id('kw').send_keys('selenium') self.driver.find_element_by_id('su').click() time.sleep(3) @classmethod def tearDownClass(cls): cls.driver.quit() if __name__ == '__main__': unittest.main()
截圖如下: