搭建关键字驱动自动化测试框架

前言

那么这篇文章我们将了解关键字驱动测试又是如何驱动自动化测试完成整个测试过程的。关键字驱动框架是一种功能自动化测试框架,它也被称为表格驱动测试或者基于动作字的测试。关键字驱动的框架的基本工作是将测试用例分成四个不同的部分。首先是测试步骤(Test Step),二是测试步骤中的对象(Test Object),三是测试对象执行的动作(Action),四是测试对象需要的数据(Test Data)。

其实我们做关键字的驱动的思想,就是把编码从测试用例和测试步骤中分离出来,这样对于不会编码的人员更容易理解自动化,从而让手工测试人员也可以编写自动脚本。(这并不意味这不需要自动化测试人员,对于自动化框架的构建,自动化代码的更新,结构调整等都需要一个技术性的人员)对于测试小的项目的团队,可以有两个手工测试人员和一个自动化测试人员。

项目功能

我们今天将要实现的功能是测试126邮箱的登录及登录后发送一封带附件的邮件

测试地址

126网易免费邮-你的专业电子邮局

项目目录

接下来我们来看看我们的项目目录是如何设计的,每个目录的功能是用来做什么的?

框架搭建

接下来我们一步一步来考虑如何搭建整个项目及每个py代码文件如何编写?

框架主要功能模块

1.新建util文件夹,并在此文件夹下新建ObjectMap.py文件,主要实现页面元素查找功能的封装

1 from selenium.webdriver.support.wait import WebDriverWait2 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 By2 from selenium.webdriver.support.wait import WebDriverWait3 from selenium.webdriver.support import expected_conditions as EC4 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 w2 import win32con3 4 class Clipboard(object):5 6     @staticmethod7     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 win32api2 import win32con3 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, date2 from config.VarConfig import *3 4 class DirAndTime(object):5     @staticmethod6     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_workbook2 from config.VarConfig import *3 from datetime import datetime, date4 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 logging2 import time3 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

业务操作功能模块

新建action文件夹,主要存储页面的各种操作,如点击操作,输入操作等1.文件夹下新建PageAction.py文件

 1 from util.ObjectMap import *2 from util.ClipboardUtil import Clipboard3 from util.KeyBoardUtil import KeyBoardKeys4 from util.WaitUntil import WaitUnit5 from util.DirAndTime import *6 from selenium import webdriver7 8 driver = None9 waitUtil = None10 # 打开浏览器11 def openBrowser(browser):12     global driver, waitUtil13     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 e23     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 e32 # 加载网址33 def loadUrl(url):34     try:35         driver.get(url)36     except Exception as e:37         raise e38 39 # 强制等待40 def sleep(sleepSeconds):41     try:42         import time43         time.sleep(sleepSeconds)44     except Exception as e:45         raise e46 # 清除输入框的内容47 def clear(by, locator):48     try:49         getElement(driver, by, locator).clear()50     except Exception as e:51         raise e52 # 输入框中输入内容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 e60 # 点击操作61 def clickBtn(by, locator):62     try:63         getElement(driver, by, locator).click()64     except Exception as e:65         raise e66 # 断言页面的title67 def assertTitle(titleStr):68     try:69         assert titleStr in driver.title, "%s not found in title!" % titleStr70     except AssertionError as e:71         raise AssertionError(e)72     except Exception as e:73         raise e74 75 # 断言目标字符串是否包含在页面源码中76 def assert_string_in_page_source(assertString):77     try:78         assert assertString in driver.page_source, "%s not found in page source!" % assertString79     except AssertionError as e:80         raise AssertionError(e)81     except Exception as e:82         raise e83 84 # 获取当前页面的title85 def getTitle():86     try:87         return driver.title88     except Exception as e:89         raise e90 91 # 获取页面源码92 def getPageSource():93     try:94         return driver.page_source95     except Exception as e:96         raise e97 # 切换到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 os3 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 ParseExcel2 from config.VarConfig import *3 from action.PageAction import *4 import traceback5 from util.log import Logger6 import logging7 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文件即可执行整个框架

最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:

在这里插入图片描述

这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!   

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/104039.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

教你如何快速阅读葡萄酒标签

我们经常被问及葡萄酒标签上写了什么,总体而言这些信息可以分为四个关键部分,第一品牌或生产商;第二国家或地区;第三葡萄品种;第四年份。 第一品牌或生产商,在寻找葡萄酒的制造商时,著名的品牌名…

论文解读 | 三维点云深度学习的综述

原创 | 文 BFT机器人 KITTI 是作为基准测试是自动驾驶中最具影响力的数据集之一,在学术界和工业界都被广泛使用。现有的三维对象检测器存在着两个限制。第一是现有方法的远程检测能力相对较差。其次,如何充分利用图像中的纹理信息仍然是一个开放性的问题…

DDD 与 CQRS 才是黄金组合

在日常工作中,你是否也遇到过下面几种情况: 使用一个已有接口进行业务开发,上线后出现严重的性能问题,被老板当众质疑:“你为什么不使用缓存接口,这个接口全部走数据库,这怎么能抗住&#xff01…

MATLAB中movmean函数用法

目录 语法 说明 示例 向量的中心移动平均值 向量的尾部移动平均值 矩阵的移动平均值 包含缺失值的向量的移动平均值 基于样本点计算移动平均值 仅返回满窗口平均值 movmean函数的功能是对数据进行移动求平均值。 语法 M movmean(A,k) M movmean(A,[kb kf]) M mov…

C++多态案例2----制作饮品

#include<iostream> using namespace std;//制作饮品的大致流程都为&#xff1a; //煮水-----冲泡-----倒入杯中----加入辅料//本案例利用多态技术&#xff0c;提供抽象类制作饮品基类&#xff0c;提供子类制作茶叶和咖啡class AbstractDrinking {public://煮水//冲水//倒…

ubuntu 22.04安装cuda、cudnn、conda、pytorch

1、cuda 视频连接 https://www.bilibili.com/video/BV1bW4y197Mo/?spm_id_from333.999.0.0&vd_source3b42b36e44d271f58e90f86679d77db7cuda 11.8 https://developer.nvidia.com/cuda-toolkit-archive点击进入 https://developer.nvidia.com/cuda-11-8-0-download-arc…

【Mysql】Mysql获取排班时间段中的休息时间段方法

在MySQL中&#xff0c;可以使用自连接&#xff08;self-join&#xff09;来获取上一条记录的结束时间和下一条记录的开始时间&#xff0c;并将它们组合成一条记录。首先&#xff0c;需要为表创建一个包含记录ID和时间信息的临时表&#xff0c;然后使用自连接获取相邻记录的时间…

【Redis7】--1.概述、安装和配置

文章目录 1.Redis概述1.1Redis是什么1.2Redis与MySQL的关系1.3Redis功能1.4Redis优势 2.Redis的安装和配置 1.Redis概述 1.1Redis是什么 Redis全称 远程字典服务器&#xff08;Remote Dictionary Server&#xff09;&#xff0c;它是完全开源的&#xff0c;使用ANSIC语言编写…

国际版阿里云/腾讯云:弹性高性能计算E-HPC入门概述

入门概述 本文介绍E-HPC的运用流程&#xff0c;帮助您快速上手运用弹性高性能核算。 下文以创立集群&#xff0c;在集群中安装GROMACS软件并运转水分子算例进行高性能核算为例&#xff0c;介绍弹性高性能核算的运用流程&#xff0c;帮助您快速上手运用弹性高性能核算。运用流程…

W25Q16_Flash手册总结

文章目录 前言一、概述&特点1、概述W25Q16BV1、特点2、引脚说明3、内部结构示意图4、操作指令5、操作示例时序图1、写入启用指令&#xff1a;Write Enable&#xff08;06h&#xff09;2、读取状态寄存器指令&#xff1a;Read Status Register-1&#xff08;05h&#xff09;…

设计模式-10--多例模式(Multition pattern)

一、什么是多例模式&#xff08;Multition pattern&#xff09; 多例模式&#xff08;Multition pattern&#xff09;是单例模式的一种扩展&#xff0c;它属于对象创建类型的设计模式。在多例模式中&#xff0c;一个类可以有多个实例&#xff0c;并且这些实例都是该类本身。因…

哈希的应用——布隆过滤器

文章目录 前言1. 布隆过滤器提出2. 布隆过滤器概念3. 布隆过滤器的插入多哈希函数映射减少冲突结构定义及set&#xff08;插入&#xff09;函数实现 4. 布隆过滤器的查找test&#xff08;查找&#xff09;函数实现布隆过滤器允许误判 5. 布隆过滤器的适用场景6. 如何选择布隆过…