一篇文章快速教你如何搭建關鍵字驅動自動化測試框架?

測試架構師百里 發佈 2022-06-24T21:17:48.093393+00:00

前言上篇文章我們已經了解到了數據驅動自動化測試框架是如何構建和驅動測試的!那麼這篇文章我們將了解關鍵字驅動測試又是如何驅動自動化測試完成整個測試過程的。關鍵字驅動框架是一種功能自動化測試框架,它也被稱為表格驅動測試或者基於動作字的測試。

前言

上篇文章我們已經了解到了數據驅動自動化測試框架是如何構建和驅動測試的!那麼這篇文章我們將了解關鍵字驅動測試又是如何驅動自動化測試完成整個測試過程的。關鍵字驅動框架是一種功能自動化測試框架,它也被稱為表格驅動測試或者基於動作字的測試。關鍵字驅動的框架的基本工作是將測試用例分成四個不同的部分。首先是測試步驟(Test Step),二是測試步驟中的對象(Test Object),三是測試對象執行的動作(Action),四是測試對象需要的數據(Test Data)。

其實我們做關鍵字的驅動的思想,就是把編碼從測試用例和測試步驟中分離出來,這樣對於不會編碼的人員更容易理解自動化,從而讓手工測試人員也可以編寫自動腳本。(這並不意味著不需要自動化測試人員,對於自動化框架的構建,自動化代碼的更新,結構調整等都需要一個技術性的人員)對於測試小的項目的團隊,可以有兩個手工測試人員和一個自動化測試人員。

一、項目功能

我們今天將要實現的功能是測試126郵箱的登錄及登錄後發送一封帶附件的郵件

測試地址

https://mail.126.com/

二、項目目錄

接下來我們來看看我們的項目目錄是如何設計的,每個目錄的功能是用來做什麼的?

三、框架搭建

接下來我們一步一步來考慮如何搭建整個項目及每個py代碼文件如何編寫?

3.1框架主要功能模塊

1.新建util文件夾,並在此文件夾下新建ObjectMap.py文件,主要實現頁面元素查找功能的封裝

 1 from selenium.webdriver.support.wait import WebDriverWait
 2 
 3 
 4 def getElement(driver, by, locator):
 5     '''
 6     查找單一元素
 7     :param driver:
 8     :param by:
 9     :param locator:
10     :return: 元素對象
11     '''
12     try:
13         element = WebDriverWait(driver, 30).until(lambda x : x.find_element(by, locator))
14     except exception as e:
15         raise e
16     else:
17         return element
18 
19 def getElements(driver, by, locator):
20     '''
21     獲取一組元素
22     :param driver:
23     :param by:
24     :param locator:
25     :return: 一組元素對象
26     '''
27     try:
28         elements = WebDriverWait(driver, 30).until(lambda x : x.find_element(by, locator))
29     except Exception as e:
30         raise e
31     else:
32         return elements
33 
34 
35 if __name__=="__main__":
36     from selenium import webdriver
37     import time
38 
39     driver = webdriver.Firefox()
40     driver.get('https://mail.126.com')
41     time.sleep(5)
42     driver.switch_to.frame(getElement(driver, 'xpath', "//div[@id='loginDiv']/iframe"))
43     username = getElement(driver, 'xpath', "//input[@name='email']")
44     username.send_keys('linuxxiaochao')
45     driver.switch_to.default_content()
46     driver.quit()

2.util文件夾下新建WaitUntil.py文件,主要實現顯示等待元素功能的封裝

 1 from selenium.webdriver.common.by import By
 2 from selenium.webdriver.support.wait import WebDriverWait
 3 from selenium.webdriver.support import expected_conditions as EC
 4 
 5 class WaitUnit(object):
 6     def __init__(self, driver):
 7         self.byDic = {
 8             'id': By.ID,
 9             'name': By.NAME,
10             'class_name': By.CLASS_NAME,
11             'xpath': By.XPATH,
12             'link_text': By.LINK_TEXT
13         }
14         self.driver = driver
15         self.wait = WebDriverWait(self.driver, 50)
16 
17     def presenceOfElementLocated(self, by, locator):
18         '''
19         顯示等待某個元素出現在dom中,不一定可見,存在返回元素對象
20         :param by:
21         :param locator:
22         :return:
23         '''
24         try:
25             if by.lower() in self.byDic:
26                 self.wait.until(EC.presence_of_element_located((self.byDic[by.lower()], locator)))
27             else:
28                 raise TypeError('未找到定位方式,請確保定位方式正確')
29         except Exception as e:
30             raise e
31 
32     def frameToBeAvailableAndSwtichToIt(self, by, locator):
33         '''
34         檢查frame是否存在,存在就切換到frame中
35         :param by:
36         :param locator:
37         :return:
38         '''
39         try:
40             if by.lower() in self.byDic:
41                 self.wait.until(EC.frame_to_be_available_and_switch_to_it((self.byDic[by.lower()], locator)))
42             else:
43                 raise TypeError('未找到定位方式,請確保定位方式正確')
44         except Exception as e:
45             raise e
46     def visibiltyOfElementLocated(self, by, locator):
47         '''
48         顯示等待頁面元素出現在dom中, 並且可見, 存在則返回該元素對象
49         :param by:
50         :param locator:
51         :return:
52         '''
53         try:
54             if by.lower() in self.byDic:
55                 self.wait.until(EC.visibility_of_element_located((self.byDic[by.lower()], locator)))
56             else:
57                 raise TypeError('未找到定位方式,請確保定位方式正確')
58         except Exception as e:
59             raise e
60 
61 if __name__=='__main__':
62     from selenium import webdriver
63     from util.ObjectMap import *
64     driver = webdriver.Firefox()
65     driver.get('https://mail.126.com')
66 
67     wait = WaitUnit(driver)
68     wait.frameToBeAvailableAndSwtichToIt('xpath', "//div[@id='loginDiv']/iframe")
69     wait.visibiltyOfElementLocated('xpath', "//input[@name='email']")
70     uname = getElement(driver, 'xpath', "//input[@name='email']")
71     uname.send_keys('python')
72     driver.quit()

3.新建ClipboardUtil.py文件,用來實現剪切版的操作(我們發送郵件時,需要添加附件,通過這個功能來實現上傳附件)

 1 import win32clipboard as w
 2 import win32con
 3 
 4 class Clipboard(object):
 5 
 6     @staticmethod
 7     def getText():
 8         '''
 9         獲取剪切板的內容
10         :return:
11         '''
12 
13         try:
14             # 打開剪切板
15             w.OpenClipboard()
16             # 讀取數據
17             value = w.GetClipboardData(win32con.CF_TEXT)
18             # 關閉剪切板
19             w.CloseClipboard()
20         except Exception as e:
21             raise e
22         else:
23             return value
24 
25     @staticmethod
26     def setText(value):
27         '''
28         設置剪切板內容
29         :return:
30         '''
31         try:
32             w.OpenClipboard()# 打開剪切板
33             w.EmptyClipboard()# 清空剪切板
34             w.SetClipboardData(win32con.CF_UNICODETEXT, value) # 設置內容
35             w.CloseClipboard() # 關閉
36         except Exception as e:
37             raise e
38 
39 if __name__=='__main__':
40     from selenium import webdriver
41 
42     value = 'python'
43     driver = webdriver.Firefox()
44     driver.get('http://www.baidu.com')
45     query = driver.find_element_by_id('kw')
46     Clipboard.setText(value)
47     clValue = Clipboard.getText()
48     query.send_keys(clValue.decode('utf-8'))

4.新建KeyBoardUtil.py文件,主要實現模擬鍵盤的操作(配合上面剪切板的功能實現,粘貼附件的路徑,回車等)

 1 import win32api
 2 import win32con
 3 
 4 class KeyBoardKeys(object):
 5     '''
 6     模擬鍵盤
 7     '''
 8     # 鍵盤編碼
 9     vk_code ={
10         'enter':0x0D,
11         'tab' : 0x09,
12         'ctrl':0x11,
13         'v':0x56
14     }
15     @staticmethod
16     def keyDown(keyName):
17         '''
18         模擬按下鍵
19         :param keyName:
20         :return:
21         '''
22         try:
23             win32api.keybd_event(KeyBoardKeys.vk_code[keyName],0,0,0)
24         except Exception as e:
25             raise e
26     @staticmethod
27     def keyUp(keyName):
28         '''
29         釋放鍵
30         :param keyName:
31         :return:
32         '''
33         try:
34             win32api.keybd_event(KeyBoardKeys.vk_code[keyName],0,win32con.KEYEVENTF_KEYUP,0)
35         except Exception as e:
36             raise e
37     @staticmethod
38     def oneKey(key):
39         '''
40         模擬當個按鍵
41         :param key:
42         :return:
43         '''
44         try:
45             KeyBoardKeys.keyDown(key)
46             KeyBoardKeys.keyUp(key)
47         except Exception as e:
48             raise e
49 
50     @staticmethod
51     def twoKeys(key1, key2):
52         '''
53         模擬組合按鍵
54         :param key1:
55         :param key2:
56         :return:
57         '''
58         try:
59             KeyBoardKeys.keyDown(key1)
60             KeyBoardKeys.keyDown(key2)
61             KeyBoardKeys.keyUp(key1)
62             KeyBoardKeys.keyUp(key2)
63         except Exception as e:
64             raise e
65 
66 if __name__=='__main__':
67     from selenium import webdriver
68 
69     driver = webdriver.Firefox()
70     driver.get('http://www.baidu.com')
71     driver.find_element_by_id('kw').send_keys('python')
72     KeyBoardKeys.oneKey('enter')

5.新建DirAndTime.py文件,主要實現獲取當前時間,生成特殊路徑,這裡主要用來生成屏幕截圖保存的路徑及圖片名稱

 1 from datetime import datetime, date
 2 from config.VarConfig import *
 3 
 4 class DirAndTime(object):
 5     @staticmethod
 6     def getCurrentDate():
 7         '''
 8         獲取當前日期
 9         :return:
10         '''
11         try:
12             currentDate = date.today()
13         except Exception as e:
14             raise e
15         else:
16             return str(currentDate)
17     @staticmethod
18     def getCurrentTime():
19         '''
20         獲取當前時間
21         :return:
22         '''
23         try:
24             Time = datetime.now()
25             currentTime = Time.strftime('%H_%M_%S')
26         except Exception as e:
27             raise e
28         else:
29             return currentTime
30     @staticmethod
31     def CreatePicturePath():
32         '''
33         創建圖片存放路徑路徑
34         :return:
35         '''
36         try:
37 
38             picturePath = os.path.join(exceptionPath , DirAndTime.getCurrentDate())
39             if not os.path.exists(picturePath):
40                 os.makedirs(picturePath) # 生成多級目錄
41         except Exception as e:
42             raise e
43         else:
44             return picturePath
45 
46 if __name__=='__main__':
47     print(DirAndTime.getCurrentDate())
48     print(DirAndTime.getCurrentTime())
49     print(DirAndTime.CreatePicturePath())

6.新建ParseExcel.py用來解析excel文件

 1 from openpyxl import load_workbook
 2 from config.VarConfig import *
 3 from datetime import datetime, date
 4 
 5 class ParseExcel(object):
 6     '''
 7     解析excel文件的封裝
 8     '''
 9     def __init__(self):
10         # 加載excel文件到內存
11         self.wb = load_workbook(excelPath)
12 
13     def getRowValue(self, sheetName, rawNo):
14         '''
15         獲取某一行的數據
16         :param sheetName:
17         :param rawNo:
18         :return: 列表
19         '''
20         sh = self.wb[sheetName]
21         rowValueList = []
22         for y in range(2, sh.max_column+1):
23             value = sh.cell(rawNo,y).value
24             rowValueList.append(value)
25         return rowValueList
26     def getColumnValue(self, sheetName, colNo):
27         '''
28         獲取某一列的數據
29         :param sheetName:
30         :param colNo:
31         :return: 列表
32         '''
33         sh = self.wb[sheetName]
34         colValueList = []
35         for x in range(2, sh.max_row +1):
36             value = sh.cell(x, colNo).value
37             colValueList.append(value)
38         return colValueList
39 
40     def getCellOfValue(self, sheetName, rowNo, colNo):
41         '''
42         獲取某一個單元格的數據
43         :param sheetName:
44         :param rowNo:
45         :param colNo:
46         :return: 字符串
47         '''
48         sh = self.wb[sheetName]
49         value = sh.cell(rowNo, colNo).value
50         return value
51     def writeCell(self, sheetName, rowNo, colNo, value):
52         '''
53         向某個單元格寫入數據
54         :param rowNo: 行號
55         :param colNo: 列號
56         :param value:
57         :return: 無
58         '''
59         sh = self.wb[sheetName]
60         sh.cell(rowNo, colNo).value = value
61         self.wb.save(excelPath)
62     def writeCurrentTime(self, sheetName, rowNo, colNo):
63         '''
64         向某個單元格寫入當前時間
65         :return:
66         '''
67         sh = self.wb[sheetName]
68         Time = datetime.now()
69         currentTime = Time.strftime('%Y:%m:%d %H:%M:%S')
70         sh.cell(rowNo, colNo).value = currentTime
71         self.wb.save(excelPath)
72 
73     def writeTestResult(self, sheetName, rowNo, result, errorInfo = None, errorPic = None):
74         ParseExcel().writeCurrentTime(sheetName, rowNo, testStep_testRunTime)
75         ParseExcel().writeCell(sheetName, rowNo, testStep_testResult, result)
76         if errorInfo and errorInfo:
77             ParseExcel().writeCell(sheetName, rowNo, testStep_testErrorInfo, errorInfo)
78             ParseExcel().writeCell(sheetName, rowNo, testStep_testErrorPic, errorPic)
79         else:
80             ParseExcel().writeCell(sheetName, rowNo, testStep_testErrorInfo, '')
81             ParseExcel().writeCell(sheetName, rowNo, testStep_testErrorPic, '')
82 if __name__=='__main__':
83     p = ParseExcel()
84     print(p.getRowValue('126account',2))
85     print(p.getColumnValue('126account',3))
86     print(p.getCellOfValue('126account', 2, 3))

7.新建Log.py文件,用來記錄代碼運行日誌

 1 import logging
 2 import time
 3 from config.VarConfig import *
 4 
 5 class Logger(object):
 6     '''
 7     封裝的日誌模塊
 8     '''
 9     def __init__(self, logger, CmdLevel=logging.INFO, FileLevel=logging.INFO):
10         """
11 
12         :param logger:
13         :param CmdLevel:
14         :param FileLevel:
15         """
16         try:
17             self.logger = logging.getLogger(logger)
18             self.logger.setLevel(logging.DEBUG)  # 設置日誌輸出的默認級別
19             # 日誌輸出格式
20             fmt = logging.Formatter('%(asctime)s - %(filename)s:[%(lineno)s] - [%(levelname)s] - %(message)s')
21             # 日誌文件名稱
22             # self.LogFileName = os.path.join(conf.log_path, "{0}.log.txt".format(time.strftime("%Y-%m-%d")))# %H_%M_%S
23             currTime = time.strftime("%Y-%m-%d")
24             self.LogFileName = logPath+currTime+'.txt'
25             # 設置控制台輸出
26             # sh = logging.StreamHandler()
27             # sh.setFormatter(fmt)
28             # sh.setLevel(CmdLevel)# 日誌級別
29 
30             # 設置文件輸出
31             fh = logging.FileHandler(self.LogFileName)
32             fh.setFormatter(fmt)
33             fh.setLevel(FileLevel)# 日誌級別
34 
35             # self.logger.addHandler(sh)
36             self.logger.addHandler(fh)
37         except Exception as e:
38             raise e
39 
40 if __name__ == '__main__':
41     logger = Logger("fox",CmdLevel=logging.DEBUG, FileLevel=logging.DEBUG)
42     logger.logger.debug("debug")
43     logger.logger.log(logging.ERROR,'%(module)s %(info)s',{'module':'log日誌','info':'error'}) #ERROR,log日誌 error

3.2業務操作功能模塊

新建action文件夾,主要存儲頁面的各種操作,如點擊操作,輸入操作等

1.文件夾下新建PageAction.py文件

  1 from util.ObjectMap import *
  2 from util.ClipboardUtil import Clipboard
  3 from util.KeyBoardUtil import KeyBoardKeys
  4 from util.WaitUntil import WaitUnit
  5 from util.DirAndTime import *
  6 from selenium import webdriver
  7 
  8 driver = None
  9 waitUtil = None
 10 # 打開瀏覽器
 11 def openBrowser(browser):
 12     global driver, waitUtil
 13     try:
 14         if browser.lower() =='ie':
 15             driver = webdriver.Ie(executable_path=iePath)
 16         elif browser.lower() == 'chrome':
 17             driver = webdriver.Chrome(executable_path=chromePath)
 18         else:
 19             # driver = webdriver.Firefox(executable_path=fireFox)
 20             driver = webdriver.Firefox()
 21     except Exception as e:
 22         raise e
 23     else:
 24         waitUtil = WaitUnit(driver) # driver 創建之後, 創建等待類實例對象
 25 
 26 # 瀏覽器窗口最大化
 27 def maximize_browser():
 28     try:
 29         driver.maximize_window()
 30     except Exception as e:
 31         raise e
 32 # 加載網址
 33 def loadUrl(url):
 34     try:
 35         driver.get(url)
 36     except Exception as e:
 37         raise e
 38 
 39 # 強制等待
 40 def sleep(sleepSeconds):
 41     try:
 42         import time
 43         time.sleep(sleepSeconds)
 44     except Exception as e:
 45         raise e
 46 # 清除輸入框的內容
 47 def clear(by, locator):
 48     try:
 49         getElement(driver, by, locator).clear()
 50     except Exception as e:
 51         raise e
 52 # 輸入框中輸入內容
 53 def inputValue(by, locator, value):
 54     try:
 55         element = getElement(driver, by, locator)
 56         # element.click()
 57         element.send_keys(value)
 58     except Exception as e:
 59         raise e
 60 # 點擊操作
 61 def clickBtn(by, locator):
 62     try:
 63         getElement(driver, by, locator).click()
 64     except Exception as e:
 65         raise e
 66 # 斷言頁面的title
 67 def assertTitle(titleStr):
 68     try:
 69         assert titleStr in driver.title, "%s not found in title!" % titleStr
 70     except AssertionError as e:
 71         raise AssertionError(e)
 72     except Exception as e:
 73         raise e
 74 
 75 # 斷言目標字符串是否包含在頁面源碼中
 76 def assert_string_in_page_source(assertString):
 77     try:
 78         assert assertString in driver.page_source, "%s not found in page source!" % assertString
 79     except AssertionError as e:
 80         raise AssertionError(e)
 81     except Exception as e:
 82         raise e
 83 
 84 # 獲取當前頁面的title
 85 def getTitle():
 86     try:
 87         return driver.title
 88     except Exception as e:
 89         raise e
 90 
 91 # 獲取頁面源碼
 92 def getPageSource():
 93     try:
 94         return driver.page_source
 95     except Exception as e:
 96         raise e
 97 # 切換到frame裡面
 98 def switchToFrame(by, locator):
 99     try:
100         driver.switch_to.frame(getElement(driver, by, locator))
101     except Exception as e:
102         raise e
103 
104 # 跳到默認的frame
105 def switchToDefault():
106     try:
107         driver.switch_to.default_content()
108     except Exception as e:
109         raise e
110 
111 # 模擬ctrl+v鍵
112 def ctrlV(value):
113     try:
114         Clipboard.setText(value)
115         sleep(2)
116         KeyBoardKeys.twoKeys('ctrl', 'v')
117     except Exception as e:
118         raise e
119 
120 # 模擬tab鍵
121 def tabKey():
122     try:
123         KeyBoardKeys.oneKey('tab')
124     except Exception as e:
125         raise e
126 
127 # 模擬enter鍵
128 def enterKey():
129     try:
130         KeyBoardKeys.oneKey('enter')
131     except Exception as e:
132         raise e
133 
134 # 屏幕截圖
135 def saveScreenShot():
136     pictureName = DirAndTime.CreatePicturePath() +'\\'+DirAndTime.getCurrentTime() + '.png'
137     try:
138         driver.get_screenshot_as_file(pictureName)
139     except Exception as e:
140         raise e
141     else:
142         return pictureName
143 
144 def waitPresenceOfElementLocated(by, locator):
145     '''
146     顯示等待頁面元素出現在DOM中,單並不一定可見
147     :param by:
148     :param locator:
149     :return:
150     '''
151     waitUtil.presenceOfElementLocated(by, locator)
152 
153 def waitFrameToBeAvailableAndSwitchToIt(by, locator):
154     '''
155     檢查frame是否存在,存在就切換到frame中
156     :param by:
157     :param locator:
158     :return:
159     '''
160     waitUtil.frameToBeAvailableAndSwtichToIt(by, locator)
161 
162 def waitVisibiltyOfElementLocated(by, locator):
163     '''
164     顯示等待頁面元素出現在DOM中,並且可見
165     :param by:
166     :param locator:
167     :return:
168     '''
169     waitUtil.visibiltyOfElementLocated(by, locator)
170 
171 # 關閉瀏覽器
172 def quitBroswer():
173     try:
174         driver.quit()
175     except Exception as e:
176         raise e
177 if __name__=='__main__':
178     openBrowser('firefox')
179     loadUrl('http://www.baidu.com')
180     # inputValue('id', 'kw','python')
181     # clear('id', 'kw')
182     # inputValue('id', 'kw', 'python')
183     # clickBtn('id', 'su')
184     # sleep(3)
185     # title = getTitle()
186     # print(title)
187     # assertTitle('python')
188     # assert_string_in_page_source('python')
189     ctrlV('python')

四、項目數據文件設計

我們既然要實現關鍵字驅動的測試,無疑是通過關鍵字數據文件來控制代碼的執行

新建testData文件夾,並新建126mailSend.xlsx文件。文件內容包括3個sheet頁,分別為測試用例,登錄,發送郵件

測試用例頁

登錄頁

發送郵件頁

注意:表格中的關鍵字 需要和PageAction.py中的方法名字保持一致

五、項目配置模塊

新建config目錄,並新建VarConfig.py文件記錄全局的目錄及excel文件部分信息

 1 # 存儲全局的變量
 2 import os
 3 
 4 # 項目根目錄
 5 projectPath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
 6 # 截圖目錄
 7 exceptionPath = projectPath +r'\exceptionpictures'
 8 
 9 # 驅動存放路徑, 需要自己根據自己電腦的驅動為止修改
10 iePath = ''
11 chromePath = ''
12 fireFox = ''
13 
14 # excel文件存放路徑
15 excelPath = projectPath + r'\testData\126mailSend.xlsx'
16 # loh文件存放路徑
17 logPath = projectPath + '\\log\\'
18 # 測試用例部分列對應的列號
19 testCase_testCaseName = 2
20 testCase_testStepName = 4
21 testCase_testIsExecute = 5
22 testCase_testRunEndTime = 6
23 testCase_testResult = 7
24 
25 # 用例步驟對應的列號
26 testStep_testNum = 1
27 testStep_testStepDescribe = 2
28 testStep_keyWord = 3
29 testStep_elementBy = 4
30 testStep_elementLocator = 5
31 testStep_operateValue = 6
32 testStep_testRunTime = 7
33 testStep_testResult = 8
34 testStep_testErrorInfo = 9
35 testStep_testErrorPic = 10
36 
37 
38 if __name__=='__main__':
39 
40     print(projectPath)
41     print(exceptionPath)

六、測試用例編寫

前期所有的準備都已經完成,接下來我們開始編寫測試用例

新建testCases文件夾,並新建Test126SendMailWithAttachment.py編寫用例

 1 from util.ParseExcel import ParseExcel
 2 from config.VarConfig import *
 3 from action.PageAction import *
 4 import traceback
 5 from util.log import Logger
 6 import logging
 7 
 8 log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
 9 p = ParseExcel()
10 sheetName = p.wb.sheetnames# 獲取到excel的所有sheet名稱
11 
12 def Test126MailSendWithAtt():
13     try:
14         testCasePassNum = 0
15 
16         requiredCase = 0
17         isExecuteColumnValues = p.getColumnValue(sheetName[0], testCase_testIsExecute)
18         # print(columnValues)
19         for index, value in enumerate(isExecuteColumnValues):
20             # print(index, value)
21             # 獲取對應的步驟sheet名稱
22             stepSheetName = p.getCellOfValue(sheetName[0],index+2, testCase_testStepName)
23             # print(stepSheetName)
24             if value.strip().lower() == 'y':
25                 requiredCase += 1
26                 testStepPassNum = 0
27                 print('開始執行測試用例"{}"'.format(stepSheetName))
28                 log.logger.info('開始執行測試用例"{}"'.format(stepSheetName))
29                 # 如果用例被標記為執行y,切換到對應的sheet頁
30                 # 獲取對應的sheet表中的總步驟數,關鍵字,定位方式,定位表達式,操作值
31                 # 步驟總數
32                 values = p.getColumnValue(stepSheetName, testStep_testNum) # 第一列數據
33                 stepNum = len(values)
34                 print(stepNum)
35                 for step in range(2, stepNum+2):
36                     rawValue = p.getRowValue(stepSheetName, step)
37                     # 執行步驟名稱
38                     stepName = rawValue[testStep_testStepDescribe -2]
39                     # 關鍵字
40                     keyWord = rawValue[testStep_keyWord - 2]
41                     # 定位方式
42                     by = rawValue[testStep_elementBy - 2]
43                     # 定位表達式
44                     locator = rawValue[testStep_elementLocator - 2]
45                     # 操作值
46                     operateValue = rawValue[testStep_operateValue - 2]
47 
48                     if keyWord and by and locator and operateValue:
49                         func = keyWord + '(' +'"' +by +'"'+ ',' +'"'+locator+ '"'+',' +'"'+ operateValue + '"'+')'
50                     elif keyWord and by and locator and operateValue is None:
51                         func = keyWord + '(' +'"' +by +'"'+ ',' +'"'+locator+ '"'+')'
52 
53                     elif keyWord and operateValue and type(operateValue) == str and by is None and locator is None:
54                         func = keyWord + '(' +'"' + operateValue + '"' + ')'
55 
56                     elif keyWord and operateValue and type(operateValue) == int and by is None and locator is None:
57                         func = keyWord + '(' + str(operateValue) +')'
58 
59                     else:
60                         func = keyWord + '('+')'
61 
62                     try:
63                         # 執行測試步驟
64                         eval(func)
65                     except Exception:
66                         # 截圖
67                         picPath = saveScreenShot()
68                         # 寫回測試結果
69                         errorInfo = traceback.format_exc()
70                         p.writeTestResult(stepSheetName, step, 'Failed', errorInfo, picPath)
71                         print('步驟"{}"執行失敗'.format(stepName))
72                         log.logger.info('步驟"{}"執行失敗'.format(stepName))
73                         raise
74                     else:
75                         print('步驟"{}"執行通過'.format(stepName))
76                         log.logger.info('步驟"{}"執行通過'.format(stepName))
77                         # 標記測試步驟為pass
78                         p.writeTestResult(stepSheetName, step, 'Pass')
79                         testStepPassNum += 1
80                 # print('通過用例步數數:',testStepPassNum)
81                 if testStepPassNum == stepNum:
82                     # 標記測試用例sheet頁的執行結果為pass
83                     p.writeCell(sheetName[0], index+2, testCase_testResult, 'Pass')
84                     testCasePassNum += 1
85                 else:
86                     p.writeCell(sheetName[0], index + 2, testCase_testResult, 'Failed')
87         print('共{}條用例,{}條需要被執行,本次執行通過{}條'.format(len(isExecuteColumnValues), requiredCase, testCasePassNum))
88         log.logger.info('共{}條用例,{}條需要被執行,本次執行通過{}條'.format(len(isExecuteColumnValues), requiredCase, testCasePassNum))
89     except Exception as e:
90         print(traceback.format_exc(e))
91         log.logger.info(traceback.format_exc(e))
92 
93 if __name__=='__main__':
94     Test126MailSendWithAtt()

七、加載用例

項目主目錄下直接新建RunTest.py,用例運行測試用例

1 if __name__=='__main__':
2     from testCases.Test126SendMailWithAttachment import Test126MailSendWithAtt
3     Test126MailSendWithAtt()

八、項目總結

1.使用外部測試數據文件,使用Excel管理測試用例的集合和每個測試用例的所有測試步驟 ,實現一個文件中完成測試用例的維護

2.每個測試用例的測試結果在一個文件中查看和統計

3.通過定義關鍵字,操作元素的定位方式及定位表達式和操作值就可以實現每個測試用例步 驟的執行,可以更加靈活地實現自動化測試的需求

4.實現定位表達式和測試代碼的分離,實現定位表達式直接在測試數據文件中進行維護。

5.框架提供日誌功能,方便調試和監控自動化測試程序的執行

6.基於關鍵字測試框架,即使不懂開發技術的測試人員也可以實施自動化測試,便於在整個 測試團隊中推廣和使用自動化測試技術,降低自動化測試實施的技術門檻

7.基於關鍵字的方式,可以進行任意關鍵字的擴展,以滿足更加複雜項目的自動化測試需求

九、運行框架

1.運行環境需要安裝了python3.x+selenium2.x;第三方模塊openpyxl,pypiwin32,
win32api, win32con
2.本地已配置chrome/firefox/ie瀏覽器及對應版本驅動
3.需要修改Excel文件中對應的用戶名和密碼
4.直接運行RunTest.py文件即可執行整個框架

總結

今天的文章就到這裡了喜歡的小夥伴可以點讚收藏評論加關注喲,關注我每天都有不同的驚喜喲。

關鍵字: