• 一篇文章快速教你如何搭建关键字驱动自动化测试框架?


    前言

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

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

    一、项目功能

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

    测试地址

    https://mail.126.com/

    二、项目目录

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

    三、框架搭建

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

    3.1框架主要功能模块

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

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

    2.util文件夹下新建WaitUntil.py文件,主要实现显示等待元素功能的封装

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

    3.新建ClipboardUtil.py文件,用来实现剪切版的操作(我们发送邮件时,需要添加附件,通过这个功能来实现上传附件)

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

    4.新建KeyBoardUtil.py文件,主要实现模拟键盘的操作(配合上面剪切板的功能实现,粘贴附件的路径,回车等)

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

    5.新建DirAndTime.py文件,主要实现获取当前时间,生成特殊路径,这里主要用来生成屏幕截图保存的路径及图片名称

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

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

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

    7.新建Log.py文件,用来记录代码运行日志

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

    3.2业务操作功能模块

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

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

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

    四、项目数据文件设计

    我们既然要实现关键字驱动的测试,无疑是通过关键字数据文件来控制代码的执行

    新建testData文件夹,并新建126mailSend.xlsx文件。文件内容包括3个sheet页,分别为测试用例,登录,发送邮件

    测试用例页

    登录页

    发送邮件页

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

    五、项目配置模块

    新建config目录,并新建VarConfig.py文件记录全局的目录及excel文件部分信息

    1. 1 # 存储全局的变量
    2. 2 import os
    3. 3
    4. 4 # 项目根目录
    5. 5 projectPath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    6. 6 # 截图目录
    7. 7 exceptionPath = projectPath +r'\exceptionpictures'
    8. 8
    9. 9 # 驱动存放路径, 需要自己根据自己电脑的驱动为止修改
    10. 10 iePath = ''
    11. 11 chromePath = ''
    12. 12 fireFox = ''
    13. 13
    14. 14 # excel文件存放路径
    15. 15 excelPath = projectPath + r'\testData\126mailSend.xlsx'
    16. 16 # loh文件存放路径
    17. 17 logPath = projectPath + '\\log\\'
    18. 18 # 测试用例部分列对应的列号
    19. 19 testCase_testCaseName = 2
    20. 20 testCase_testStepName = 4
    21. 21 testCase_testIsExecute = 5
    22. 22 testCase_testRunEndTime = 6
    23. 23 testCase_testResult = 7
    24. 24
    25. 25 # 用例步骤对应的列号
    26. 26 testStep_testNum = 1
    27. 27 testStep_testStepDescribe = 2
    28. 28 testStep_keyWord = 3
    29. 29 testStep_elementBy = 4
    30. 30 testStep_elementLocator = 5
    31. 31 testStep_operateValue = 6
    32. 32 testStep_testRunTime = 7
    33. 33 testStep_testResult = 8
    34. 34 testStep_testErrorInfo = 9
    35. 35 testStep_testErrorPic = 10
    36. 36
    37. 37
    38. 38 if __name__=='__main__':
    39. 39
    40. 40 print(projectPath)
    41. 41 print(exceptionPath)

    六、测试用例编写

    前期所有的准备都已经完成,接下来我们开始编写测试用例

    新建testCases文件夹,并新建Test126SendMailWithAttachment.py编写用例

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

    七、加载用例

    项目主目录下直接新建RunTest.py,用例运行测试用例

    1. 1 if __name__=='__main__':
    2. 2 from testCases.Test126SendMailWithAttachment import Test126MailSendWithAtt
    3. 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文件即可执行整个框架

    总结

    今天的文章就到这里了喜欢的小伙伴可以点赞收藏评论加关注哟,关注我每天都有不同的惊喜哟。

  • 相关阅读:
    python抓取网页视频
    架构师必备:HBase行键设计与应用
    虚拟机没有桥接模式--物理机WiFi不见了--注册表修复
    隐马尔可夫过程
    Redis——主从复制(一主两从)
    根据PPG估算血压利用频谱谱-时间深度神经网络【翻】
    ConcurrentHashMap解析
    【扩展阅读之编译和解释语言的区别】
    QT—信号与槽详解
    通过Power Platform自定义D365 CE 业务需求 - 10.使用Power Apps和Dynamics 365的集成
  • 原文地址:https://blog.csdn.net/ifling99/article/details/125452817