Python Selenium 关键字驱动

news2024/11/24 20:58:37

目录

项目目录结构

 action目录

config目录

exceptionpictures目录

log目录

testCases目录

testData目录

util目录

 总结


之前写过一篇Java版的关键字驱动,现在来写一篇Python版本的,网上好多教程都是虎头蛇尾的不完整~

说下思路,这边没有用Python反射去获取方法名去执行关键字,而是通过Python内置函数eval()来拼接字符串组成关键字然后一并执行,这个用法比较妙!Python eval()内置函数具体用法可自行百度。

项目目录结构

先看下目录结构:

 action目录

action目录主要存放关键字模块:PageAction.py,封装了一些基本的web操作方法,如点击、输入、查找等,具体代码如下:

from seleniumkeyword.util.ObjectMap import *
from seleniumkeyword.util.ClipboardUtil import Clipboard
from seleniumkeyword.util.KeyBoardUtil import KeyBoardKeys
from seleniumkeyword.util.WaitUntil import WaitUnit
from seleniumkeyword.util.DirAndTime import *
from selenium import webdriver

driver = None
waitUtil = None


# 打开浏览器
def openBrowser(browser):
    global driver, waitUtil
    try:
        if browser.lower() == 'ie':
            driver = webdriver.Ie(executable_path=iePath)
        elif browser.lower() == 'chrome':
            driver = webdriver.Chrome(executable_path=chromePath)
        else:
            # driver = webdriver.Firefox(executable_path=fireFox)
            driver = webdriver.Firefox()
    except Exception as e:
        raise e
    else:
        waitUtil = WaitUnit(driver)  # driver 创建之后, 创建等待类实例对象


# 浏览器窗口最大化
def maximize_browser():
    try:
        driver.maximize_window()
    except Exception as e:
        raise e


# 加载网址
def loadUrl(url):
    try:
        driver.get(url)
    except Exception as e:
        raise e


# 强制等待
def sleep(sleepSeconds):
    try:
        import time
        time.sleep(sleepSeconds)
    except Exception as e:
        raise e


# 清除输入框的内容
def clear(by, locator):
    try:
        getElement(driver, by, locator).clear()
    except Exception as e:
        raise e


# 输入框中输入内容
def inputValue(by, locator, value):
    try:
        element = getElement(driver, by, locator)
        # element.click()
        element.send_keys(value)
    except Exception as e:
        raise e


# 点击操作
def clickBtn(by, locator):
    try:
        getElement(driver, by, locator).click()
    except Exception as e:
        raise e


# 断言页面的title
def assertTitle(titleStr):
    try:
        assert titleStr in driver.title, "%s not found in title!" % titleStr
    except AssertionError as e:
        raise AssertionError(e)
    except Exception as e:
        raise e


# 断言目标字符串是否包含在页面源码中
def assert_string_in_page_source(assertString):
    try:
        assert assertString in driver.page_source, "%s not found in page source!" % assertString
    except AssertionError as e:
        raise AssertionError(e)
    except Exception as e:
        raise e


# 获取当前页面的title
def getTitle():
    try:
        return driver.title
    except Exception as e:
        raise e


# 获取页面源码
def getPageSource():
    try:
        return driver.page_source
    except Exception as e:
        raise e


# 切换到frame里面
def switchToFrame(by, locator):
    try:
        driver.switch_to.frame(getElement(driver, by, locator))
    except Exception as e:
        raise e


# 跳到默认的frame
def switchToDefault():
    try:
        driver.switch_to.default_content()
    except Exception as e:
        raise e


# 模拟ctrl+v键
def ctrlV(value):
    try:
        Clipboard.setText(value)
        sleep(2)
        KeyBoardKeys.twoKeys('ctrl', 'v')
    except Exception as e:
        raise e


# 模拟tab键
def tabKey():
    try:
        KeyBoardKeys.oneKey('tab')
    except Exception as e:
        raise e


# 模拟enter键
def enterKey():
    try:
        KeyBoardKeys.oneKey('enter')
    except Exception as e:
        raise e


# 屏幕截图
def saveScreenShot():
    pictureName = DirAndTime.CreatePicturePath() + '\\' + DirAndTime.getCurrentTime() + '.png'
    try:
        driver.get_screenshot_as_file(pictureName)
    except Exception as e:
        raise e
    else:
        return pictureName


def waitPresenceOfElementLocated(by, locator):
    '''
    显示等待页面元素出现在DOM中,单并不一定可见
    :param by:
    :param locator:
    :return:
    '''
    waitUtil.presenceOfElementLocated(by, locator)


def waitFrameToBeAvailableAndSwitchToIt(by, locator):
    '''
    检查frame是否存在,存在就切换到frame中
    :param by:
    :param locator:
    :return:
    '''
    waitUtil.frameToBeAvailableAndSwtichToIt(by, locator)


def waitVisibiltyOfElementLocated(by, locator):
    '''
    显示等待页面元素出现在DOM中,并且可见
    :param by:
    :param locator:
    :return:
    '''
    waitUtil.visibiltyOfElementLocated(by, locator)


# 关闭浏览器
def quitBroswer():
    try:
        driver.quit()
    except Exception as e:
        raise e


if __name__ == '__main__':
    openBrowser('firefox')
    loadUrl('http://www.baidu.com')
    # inputValue('id', 'kw','python')
    # clear('id', 'kw')
    # inputValue('id', 'kw', 'python')
    # clickBtn('id', 'su')
    # sleep(3)
    # title = getTitle()
    # print(title)
    # assertTitle('python')
    # assert_string_in_page_source('python')
    ctrlV('python')

config目录

主要是一些配置 参数和常量,VarConfig.py,如果用的selenium 4和webdriver manager的话可以不用定义驱动路径,代码运行会自动安装对应的驱动程序。

具体代码如下:

# 存储全局的变量
import os

# 项目根目录
projectPath = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 截图目录
exceptionPath = projectPath + r'\exceptionpictures'

# 驱动存放路径, 需要自己根据自己电脑的驱动为止修改
iePath = ''
chromePath = 'C:\\Users\\Maven\\.wdm\\drivers\\chromedriver\\win32\\109.0.5414.74\\chromedriver.exe'
fireFox = ''

# excel文件存放路径
excelPath = projectPath + r'\testData\keywords.xlsx'
# loh文件存放路径
logPath = projectPath + '\\log\\'
# 测试用例部分列对应的列号
testCase_testCaseName = 2
testCase_testStepName = 4
testCase_testIsExecute = 5
testCase_testRunEndTime = 6
testCase_testResult = 7

# 用例步骤对应的列号
testStep_testNum = 1
testStep_testStepDescribe = 2
testStep_keyWord = 3
testStep_elementBy = 4
testStep_elementLocator = 5
testStep_operateValue = 6
testStep_testRunTime = 7
testStep_testResult = 8
testStep_testErrorInfo = 9
testStep_testErrorPic = 10

if __name__ == '__main__':
    print(projectPath)
    print(exceptionPath)

exceptionpictures目录

主要存放用例异常时的截图

log目录

存放执行日志

testCases目录

存放测试用例,用例示例代码如下:

from seleniumkeyword.util.ParseExcel import ParseExcel
from seleniumkeyword.config.VarConfig import *
from seleniumkeyword.action.PageAction import *
import traceback
from seleniumkeyword.util.Log import Logger
import logging

log = Logger(__name__, CmdLevel=logging.INFO, FileLevel=logging.INFO)
p = ParseExcel()
sheetName = p.wb.sheetnames  # 获取到excel的所有sheet名称


def TestKeywords():
    try:
        testCasePassNum = 0

        requiredCase = 0
        isExecuteColumnValues = p.getColumnValue(sheetName[0], testCase_testIsExecute)
        print(isExecuteColumnValues)
        print(len(isExecuteColumnValues))
        for index, value in enumerate(isExecuteColumnValues):
            print(index, value)
            # 获取对应的步骤sheet名称
            stepSheetName = p.getCellOfValue(sheetName[0], index + 2, testCase_testStepName)
            # print(stepSheetName)
            if value is not None and value.strip().lower() == 'y':
                requiredCase += 1
                testStepPassNum = 0
                print('开始执行测试用例"{}"'.format(stepSheetName))
                log.logger.info('开始执行测试用例"{}"'.format(stepSheetName))
                # 如果用例被标记为执行y,切换到对应的sheet页
                # 获取对应的sheet表中的总步骤数,关键字,定位方式,定位表达式,操作值
                # 步骤总数
                values = p.getColumnValue(stepSheetName, testStep_testNum)  # 第一列数据
                stepNum = len(values)
                print(stepNum)
                for step in range(2, stepNum + 2):
                    rawValue = p.getRowValue(stepSheetName, step)
                    # 执行步骤名称
                    stepName = rawValue[testStep_testStepDescribe - 2]
                    # 关键字
                    keyWord = rawValue[testStep_keyWord - 2]
                    # 定位方式
                    by = rawValue[testStep_elementBy - 2]
                    # 定位表达式
                    locator = rawValue[testStep_elementLocator - 2]
                    # 操作值
                    operateValue = rawValue[testStep_operateValue - 2]

                    if keyWord and by and locator and operateValue:
                        func = keyWord + '(' + '"' + by + '"' + ',' + '"' + locator + '"' + ',' + '"' + operateValue + '"' + ')'
                    elif keyWord and by and locator and operateValue is None:
                        func = keyWord + '(' + '"' + by + '"' + ',' + '"' + locator + '"' + ')'

                    elif keyWord and operateValue and type(operateValue) == str and by is None and locator is None:
                        func = keyWord + '(' + '"' + operateValue + '"' + ')'

                    elif keyWord and operateValue and type(operateValue) == int and by is None and locator is None:
                        func = keyWord + '(' + str(operateValue) + ')'

                    else:
                        func = keyWord + '(' + ')'

                    try:
                        # 执行测试步骤
                        eval(func)
                    except Exception:
                        # 截图
                        picPath = saveScreenShot()
                        # 写回测试结果
                        errorInfo = traceback.format_exc()
                        p.writeTestResult(stepSheetName, step, 'Failed', errorInfo, picPath)
                        print('步骤"{}"执行失败'.format(stepName))
                        log.logger.info('步骤"{}"执行失败'.format(stepName))

                    else:
                        print('步骤"{}"执行通过'.format(stepName))
                        log.logger.info('步骤"{}"执行通过'.format(stepName))
                        # 标记测试步骤为pass
                        p.writeTestResult(stepSheetName, step, 'Pass')
                        testStepPassNum += 1
                # print('通过用例步数数:',testStepPassNum)
                if testStepPassNum == stepNum:
                    # 标记测试用例sheet页的执行结果为pass
                    p.writeTestCaseResult(sheetName[0], index + 2, 'Pass')
                    testCasePassNum += 1
                else:
                    p.writeTestCaseResult(sheetName[0], index + 2, 'Failed')

        print('共{}条用例,{}条需要被执行,本次执行通过{}条'.format(len(isExecuteColumnValues), requiredCase, testCasePassNum))
        log.logger.info('共{}条用例,{}条需要被执行,本次执行通过{}条'.format(len(isExecuteColumnValues), requiredCase, testCasePassNum))
    except Exception as e:
        print(traceback.format_exc(e))
        log.logger.info(traceback.format_exc(e))


if __name__ == '__main__':
    TestKeywords()

testData目录

存放Excel的关键字用例:keywords.xlsx,主要分两块,一块是用例的汇总信息见表一(表名:测试用例),一个是用例的具体执行信息,见表二(表名:百度搜索)、表三(表名:登录):

序号用例名称用例描述步骤名是否执行执行结束时间结果
1百度搜索百度搜索百度搜索y2023:04:18 22:45:58Pass
2登录126邮箱使用无效的账号登录126邮箱登录y2023:04:18 22:48:38Failed

                                                   

 

根据表一即“测试用例”表是否执行列取值为y则执行步骤列对应表二表三中的关键字,注意这个要一一对应不然会报错!

util目录

封装一些常用的操作,如读写Excel,时间操作,等待操作,查找操作等,具体类如下:

ClipboardUtil.py,封装复制粘贴方法
import win32clipboard as w
import win32con


class Clipboard(object):

    @staticmethod
    def getText():
        '''
        获取剪切板的内容
        :return:
        '''

        try:
            # 打开剪切板
            w.OpenClipboard()
            # 读取数据
            value = w.GetClipboardData(win32con.CF_TEXT)
            # 关闭剪切板
            w.CloseClipboard()
        except Exception as e:
            raise e
        else:
            return value

    @staticmethod
    def setText(value):
        '''
        设置剪切板内容
        :return:
        '''
        try:
            w.OpenClipboard()  # 打开剪切板
            w.EmptyClipboard()  # 清空剪切板
            w.SetClipboardData(win32con.CF_UNICODETEXT, value)  # 设置内容
            w.CloseClipboard()  # 关闭
        except Exception as e:
            raise e


if __name__ == '__main__':
    from selenium import webdriver

    value = 'python'
    driver = webdriver.Firefox()
    driver.get('http://www.baidu.com')
    query = driver.find_element_by_id('kw')
    Clipboard.setText(value)
    clValue = Clipboard.getText()
    query.send_keys(clValue.decode('utf-8'))
DirAndTime.py,文件和时间的一些封装
from datetime import datetime, date
from seleniumkeyword.config.VarConfig import *
import os


class DirAndTime(object):
    @staticmethod
    def getCurrentDate():
        '''
        获取当前日期
        :return:
        '''
        try:
            currentDate = date.today()
        except Exception as e:
            raise e
        else:
            return str(currentDate)

    @staticmethod
    def getCurrentTime():
        '''
        获取当前时间
        :return:
        '''
        try:
            Time = datetime.now()
            currentTime = Time.strftime('%H_%M_%S')
        except Exception as e:
            raise e
        else:
            return currentTime

    @staticmethod
    def CreatePicturePath():
        '''
        创建图片存放路径路径
        :return:
        '''
        try:

            picturePath = os.path.join(exceptionPath, DirAndTime.getCurrentDate())
            if not os.path.exists(picturePath):
                os.makedirs(picturePath)  # 生成多级目录
        except Exception as e:
            raise e
        else:
            return picturePath


if __name__ == '__main__':
    print(DirAndTime.getCurrentDate())
    print(DirAndTime.getCurrentTime())
    print(DirAndTime.CreatePicturePath())
KeyBoardUtil.py封装一些键盘鼠标操作
import win32api
import win32con


class KeyBoardKeys(object):
    '''
    模拟键盘
    '''
    # 键盘编码
    vk_code = {
        'enter': 0x0D,
        'tab': 0x09,
        'ctrl': 0x11,
        'v': 0x56
    }

    @staticmethod
    def keyDown(keyName):
        '''
        模拟按下键
        :param keyName:
        :return:
        '''
        try:
            win32api.keybd_event(KeyBoardKeys.vk_code[keyName], 0, 0, 0)
        except Exception as e:
            raise e

    @staticmethod
    def keyUp(keyName):
        '''
        释放键
        :param keyName:
        :return:
        '''
        try:
            win32api.keybd_event(KeyBoardKeys.vk_code[keyName], 0, win32con.KEYEVENTF_KEYUP, 0)
        except Exception as e:
            raise e

    @staticmethod
    def oneKey(key):
        '''
        模拟当个按键
        :param key:
        :return:
        '''
        try:
            KeyBoardKeys.keyDown(key)
            KeyBoardKeys.keyUp(key)
        except Exception as e:
            raise e

    @staticmethod
    def twoKeys(key1, key2):
        '''
        模拟组合按键
        :param key1:
        :param key2:
        :return:
        '''
        try:
            KeyBoardKeys.keyDown(key1)
            KeyBoardKeys.keyDown(key2)
            KeyBoardKeys.keyUp(key1)
            KeyBoardKeys.keyUp(key2)
        except Exception as e:
            raise e


if __name__ == '__main__':
    from selenium import webdriver

    driver = webdriver.Firefox()
    driver.get('http://www.baidu.com')
    driver.find_element_by_id('kw').send_keys('python')
    KeyBoardKeys.oneKey('enter')
Log.py:封装日志类
import logging
import time
from seleniumkeyword.config.VarConfig import *


class Logger(object):
    '''
    封装的日志模块
    '''

    def __init__(self, logger, CmdLevel=logging.INFO, FileLevel=logging.INFO):
        """

        :param logger:
        :param CmdLevel:
        :param FileLevel:
        """
        try:
            self.logger = logging.getLogger(logger)
            self.logger.setLevel(logging.DEBUG)  # 设置日志输出的默认级别
            # 日志输出格式
            fmt = logging.Formatter('%(asctime)s - %(filename)s:[%(lineno)s] - [%(levelname)s] - %(message)s')
            # 日志文件名称
            # self.LogFileName = os.path.join(conf.log_path, "{0}.log.txt".format(time.strftime("%Y-%m-%d")))# %H_%M_%S
            currTime = time.strftime("%Y-%m-%d")
            self.LogFileName = logPath + currTime + '.txt'
            # 设置控制台输出
            # sh = logging.StreamHandler()
            # sh.setFormatter(fmt)
            # sh.setLevel(CmdLevel)# 日志级别

            # 设置文件输出
            fh = logging.FileHandler(self.LogFileName)
            fh.setFormatter(fmt)
            fh.setLevel(FileLevel)  # 日志级别

            # self.logger.addHandler(sh)
            self.logger.addHandler(fh)
        except Exception as e:
            raise e


if __name__ == '__main__':
    logger = Logger("fox", CmdLevel=logging.DEBUG, FileLevel=logging.DEBUG)
    logger.logger.debug("debug")
    logger.logger.log(logging.ERROR, '%(module)s %(info)s', {'module': 'log日志', 'info': 'error'})  # ERROR,log日志 error
ObjectMap.py:封装selenium查找方法
from selenium.webdriver.support.wait import WebDriverWait


def getElement(driver, by, locator):
    '''
    查找单一元素
    :param driver:
    :param by:
    :param locator:
    :return: 元素对象
    '''
    try:
        element = WebDriverWait(driver, 30).until(lambda x: x.find_element(by, locator))
    except Exception as e:
        raise e
    else:
        return element


def getElements(driver, by, locator):
    '''
    获取一组元素
    :param driver:
    :param by:
    :param locator:
    :return: 一组元素对象
    '''
    try:
        elements = WebDriverWait(driver, 30).until(lambda x: x.find_element(by, locator))
    except Exception as e:
        raise e
    else:
        return elements


if __name__ == "__main__":
    from selenium import webdriver
    import time

    driver = webdriver.Firefox()
    driver.get('https://mail.126.com')
    time.sleep(5)
    driver.switch_to.frame(getElement(driver, 'xpath', "//div[@id='loginDiv']/iframe"))
    username = getElement(driver, 'xpath', "//input[@name='email']")
    username.send_keys('linuxxiaochao')
    driver.switch_to.default_content()
    driver.quit()
ParseExcel.py:Excel解析、创建
from openpyxl import load_workbook
from openpyxl.styles import colors
from openpyxl.styles import Font, Color
from seleniumkeyword.config.VarConfig import *
from datetime import datetime, date


class ParseExcel(object):
    '''
    解析excel文件的封装
    '''

    def __init__(self):
        # 加载excel文件到内存
        self.wb = load_workbook(excelPath)

    def getRowValue(self, sheetName, rawNo):
        '''
        获取某一行的数据
        :param sheetName:
        :param rawNo:
        :return: 列表
        '''
        sh = self.wb[sheetName]
        rowValueList = []
        for y in range(2, sh.max_column + 1):
            value = sh.cell(rawNo, y).value
            rowValueList.append(value)
        return rowValueList

    def getColumnValue(self, sheetName, colNo):
        '''
        获取某一列的数据
        :param sheetName:
        :param colNo:
        :return: 列表
        '''
        sh = self.wb[sheetName]
        colValueList = []
        print('待执行用例最大行数'+str(sh.max_row-1))
        for x in range(2, sh.max_row+1):
            value = sh.cell(x, colNo).value
            colValueList.append(value)
        return colValueList

    def getCellOfValue(self, sheetName, rowNo, colNo):
        '''
        获取某一个单元格的数据
        :param sheetName:
        :param rowNo:
        :param colNo:
        :return: 字符串
        '''
        sh = self.wb[sheetName]
        value = sh.cell(rowNo, colNo).value
        return value

    def writeCell(self, sheetName, rowNo, colNo, value):
        '''
        向某个单元格写入数据
        :param rowNo: 行号
        :param colNo: 列号
        :param value:
        :return: 无
        '''
        sh = self.wb[sheetName]
        sh.cell(rowNo, colNo).value = value
        if value=='Pass':
            ft = Font(color="00008000")
        else:
            ft = Font(color="00FF0000")
        sh.cell(rowNo, colNo).font = ft
        self.wb.save(excelPath)

    def writeCurrentTime(self, sheetName, rowNo, colNo):
        '''
        向某个单元格写入当前时间
        :return:
        '''
        sh = self.wb[sheetName]
        ft = Font(color="00000000")
        sh.cell(rowNo, colNo).font = ft
        Time = datetime.now()
        currentTime = Time.strftime('%Y:%m:%d %H:%M:%S')
        sh.cell(rowNo, colNo).value = currentTime
        self.wb.save(excelPath)

    def writeTestResult(self, sheetName, rowNo, result, errorInfo=None, errorPic=None):
        self.writeCurrentTime(sheetName, rowNo, testStep_testRunTime)
        self.writeCell(sheetName, rowNo, testStep_testResult, result)
        if errorInfo and errorInfo:
            self.writeCell(sheetName, rowNo, testStep_testErrorInfo, errorInfo)
            self.writeCell(sheetName, rowNo, testStep_testErrorPic, errorPic)
        else:
            self.writeCell(sheetName, rowNo, testStep_testErrorInfo, '')
            self.writeCell(sheetName, rowNo, testStep_testErrorPic, '')

    def writeTestCaseResult(self, sheetName, rowNo, result):
        self.writeCurrentTime(sheetName, rowNo, testCase_testRunEndTime)
        self.writeCell(sheetName, rowNo, testCase_testResult, result)


if __name__ == '__main__':
    p = ParseExcel()
    print(p.getRowValue('126account', 2))
    print(p.getColumnValue('126account', 3))
    print(p.getCellOfValue('126account', 2, 3))
WaitUntil.py:selenium 等待方法的封装
from selenium.webdriver.common.by import By
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from seleniumkeyword.util.ObjectMap import *


class WaitUnit(object):
    def __init__(self, driver):
        self.byDic = {
            'id': By.ID,
            'name': By.NAME,
            'class_name': By.CLASS_NAME,
            'xpath': By.XPATH,
            'link_text': By.LINK_TEXT
        }
        self.driver = driver
        self.wait = WebDriverWait(self.driver, 50)

    def presenceOfElementLocated(self, by, locator):
        '''
        显示等待某个元素出现在dom中,不一定可见,存在返回元素对象
        :param by:
        :param locator:
        :return:
        '''
        try:
            if by.lower() in self.byDic:
                self.wait.until(EC.presence_of_element_located((self.byDic[by.lower()], locator)))
            else:
                raise TypeError('未找到定位方式,请确保定位方式正确')
        except Exception as e:
            raise e

    def frameToBeAvailableAndSwtichToIt(self, by, locator):
        '''
        检查frame是否存在,存在就切换到frame中
        :param by:
        :param locator:
        :return:
        '''
        try:
            if by.lower() in self.byDic:
                self.wait.until(EC.frame_to_be_available_and_switch_to_it((self.byDic[by.lower()], locator)))
            else:
                raise TypeError('未找到定位方式,请确保定位方式正确')
        except Exception as e:
            raise e

    def visibiltyOfElementLocated(self, by, locator):
        '''
        显示等待页面元素出现在dom中, 并且可见, 存在则返回该元素对象
        :param by:
        :param locator:
        :return:
        '''
        try:
            if by.lower() in self.byDic:
                self.wait.until(EC.visibility_of_element_located((self.byDic[by.lower()], locator)))
            else:
                raise TypeError('未找到定位方式,请确保定位方式正确')
        except Exception as e:
            raise e


if __name__ == '__main__':
    from selenium import webdriver

    driver = webdriver.Firefox()
    driver.get('https://mail.126.com')

    wait = WaitUnit(driver)
    wait.frameToBeAvailableAndSwtichToIt('xpath', "//div[@id='loginDiv']/iframe")
    wait.visibiltyOfElementLocated('xpath', "//input[@name='email']")
    uname = getElement(driver, 'xpath', "//input[@name='email']")
    uname.send_keys('python')
    driver.quit()
RunTest.py:测试运行类
from seleniumkeyword.testCases.TestKeyWords import TestKeyWords

if __name__ == '__main__':
    TestKeyWords()

测试执行如下:

 总结

实际情况下这些关键字太细使用过程中如果场景复杂要填的表格项会非常多,因此需要封装一些常用的关键字比如登录,退出登录等操作,这里给个思路,因为Python eval 函数是拼接字符串执行的,因此其实定位方法和操作值里填一个参数或者多个参数都是一样的,关键在于怎么去把多个参数分隔成想要的数据。如通常登录至少包含3个查找元素:用户输入、密码输入、登录,那么在填写登录关键字的时候就可以这样填:

序号测试步骤描述关键字操作操作元素的定位表达式操作值
1登录loginid,id,xpathloc1,loc2,locvalue1,value2

然后封装关键字的时候注意分隔参数这样就能实现复杂的关键字封装~

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

十、ElasticSearch 实战 - 源码运行

一、概述 想深入理解 Elasticsearch,了解其报错机制,并有针对性的调整参数,阅读其源码是很有必要的。此外,了解优秀开源项目的代码架构,能够提高个人的代码架构能力 阅读 Elasticsearch 源码的第一步是搭建调试环境&…

C++的左值引用和右值引用

引用和指针的区别? 引用必须初始化,指针可以不初始化 定义一个指针和引用汇编指令上一样的,引用底层还是指针 引用只有一级引用,没有多级引用,而指针可以有多级指针 定义一个引用变量和指针变量,它们汇…

【c语言】函数指针详解

创作不易&#xff0c;本篇文章如果帮助到了你&#xff0c;还请点赞支持一下♡>&#x16966;<)!! 主页专栏有更多知识&#xff0c;如有疑问欢迎大家指正讨论&#xff0c;共同进步&#xff01; 给大家跳段街舞感谢支持&#xff01;ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ…

Android Framework—Service

介绍 Service是一种可以在后台执行长时间运行操作而不提供界面的应用组件。服务可以由其他应用组件启动&#xff0c;而且即使用户切换到其他应用&#xff0c;服务仍将在后台继续运行。此外&#xff0c;组件可以通过绑定到服务与之进行交互&#xff0c;甚至是执行进程之间的通信…

Unreal5 第三人称射击游戏 角色基础制作

快捷键 快捷键 ctrlE 可以快速打开相关蓝图类&#xff0c;直接在场景选中添加到场景中的对象即可。 调试蓝图 选中调试对象&#xff0c;选中需要调试的实例&#xff0c;即可查看当前角色的状态。 动画实例在运行的时候&#xff0c;也可以在右侧箭头获取当前场景已经生成的实…

Linux socket编程(二):多进程服务器

一、多进程服务器 最简单的的服务器程序执行流程为&#xff1a;创建socket → \rightarrow → 绑定监听的IP地址和端口 → \rightarrow → 监听客户端连接 → \rightarrow → 接受/发送数据。当服务端调用read阻塞等待一个客户端发来数据时&#xff0c;无法同时响应其它客户…

七、CANdelaStudio入门-Variant概念与应用

本专栏将由浅入深的展开诊断实际开发与测试的数据库编辑,包含大量实际开发过程中的步骤、使用技巧与少量对Autosar标准的解读。希望能对大家有所帮助,与大家共同成长,早日成为一名车载诊断、通信全栈工程师。 本文介绍CANdelaStudio的Variant概念与应用,欢迎各位朋友订阅、…

Redis实现互相关注功能

Redis实现互相关注功能 我们要实现关注功能&#xff0c;首先&#xff0c;我们需要得到关注的目标ID&#xff1a; PutMapping("/{id}/{isFollow}")public Result followUser(PathVariable("id") Long id,PathVariable("isFollow") Boolean isFol…

下一代大数据分布式存储技术Apache Ozone初步研究

文章目录 概述定义特性架构总体架构写数据读数据 部署安装方式安装Docker启动Docker-compose启动企业预置型(On Premise)安装 实践命令行接口Ofs (Hadoop兼容)Recon API 概述 定义 Apache Ozone 官网地址 https://ozone.apache.org/ 最新版本1.3.0 Apache Ozone 官网最新文档地…

Java线程间通信方式(2)

前文了解了线程通信方式中的Object.wait/Object.notify以及Semaphore,接下来我们继续了解其他的线程间通信方式。 CountDownLatch CountDownLatch利用一个指定的计数初始化&#xff0c;由于调用了countDown方法&#xff0c;await方法会阻塞直到当前技术为0&#xff0c;之后所…

PHP-8.2.5+IIS10 php-cgi.exe - FastCGI 进程意外退出

服务器信息&#xff1a; Windows Server 2019 Standard. Internet Information Services(Version 10.0.17763.1) PHP版本&#xff1a; PHP Version 8.2.5 php-8.2.5-nts-Win32-vs16-x64 下载地址&#xff1a;https://windows.php.net/download#php-8.2 错误信息&#xff1a; H…

【网络】-- UDP协议

目录 传输层 再谈端口号 端口号范围划分 认识知名端口号&#xff08;Well-Know Port Number&#xff09; 两个问题 netstat pidof UDP协议 UDP的特点 UDP的缓冲区 UDP使用注意事项 基于UDP的应用层协议 传输层 负责数据能够从发送端传输接收端。 再谈端口号 端…

【ROS】ubuntu18.04安装ROS(ROS1 Melodic)

1、添加中科大ROS源 1.1、添加源 sudo sh -c . /etc/lsb-release && echo "deb http://mirrors.ustc.edu.cn/ros/ubuntu/ lsb_release -cs main" > /etc/apt/sources.list.d/ros-latest.list1. 2、添加公钥 sudo apt-key adv --keyserver hkp://keyser…

输入捕获实验

实验内容 用TIM5 的通道 1&#xff08;PA0&#xff09;来做输入捕获&#xff0c;捕获 PA0 上高电平的脉宽&#xff08;用 WK_UP 按键输入高电平&#xff09;&#xff0c;通过串口打印高电平脉宽时间。 输入捕获简介 输入捕获模式可以用来测量脉冲宽度或者测量频率。STM32 的…

新库上线 | 全国工艺美术大师信息数据

全国工艺美术大师信息数据 一、数据简介 作为物质产品&#xff0c;工艺美术反映着一定时代、一定社会的物质的和文化的生产水平&#xff1b;作为精神产品&#xff0c;它的视觉形象&#xff08;造型、色彩、装饰&#xff09;又体现了一定时代的审美观。我国工艺美术品的制作较早…

java基础+注解笔记【狂神说java】

基础部分–总结 基础包的命名 //一般为域名倒置 page com.yang.base基础语法 类和方法 根据不同的写法–大小写的差异可以判别是类对象还是方法名 类的首字母都要大写&#xff0c;方法首字母小写可以理解为&#xff0c;类对象是class&#xff0c;方法是函数 类对象 方法 使…

浅谈在 Vue2 和 Vue3 中计算属性和侦听器的一些变化

文章目录 &#x1f4cb;前言&#x1f3af;计算属性&#x1f3af;侦听器&#x1f4dd;最后 &#x1f4cb;前言 计算属性 computed 和侦听器 watch 都是 Vue.js 框架中用来响应式更新视图的重要概念。因此无论是在哪个版本&#xff0c;它们都是不可缺少的概念&#xff0c;这篇文…

音视频八股文(5)--SDL音视频渲染实战。会使用就行,不需要深究。

01-SDL子系统 SDL将功能分成下列数个子系统&#xff08;subsystem&#xff09;&#xff1a; ◼ SDL_INIT_TIMER&#xff1a;定时器 ◼ SDL_INIT_AUDIO&#xff1a;音频 ◼ SDL_INIT_VIDEO&#xff1a;视频 ◼ SDL_INIT_JOYSTICK&#xff1a;摇杆 ◼ SDL_INIT_HAPTIC&#xff1…

第十三章 享元模式

文章目录 前言一、享元模式基本介绍二、享元模式解决网站展现项目完整代码WebSite 抽象网站类User 外部状态用户内部状态网站 ConcreteWebSite网站工厂产生网站和负责共享&#xff08;池&#xff09; WebSiteFactoryClint 测试 三、享元模式在JDK-Interger的应用源码分析四、享…

ERBuilder Data Modeler Crack

ERBuilder Data Modeler Crack 为过程、视图和触发器添加了人工智能驱动的描述生成。 添加了一种新的自动排列方法&#xff0c;可以轻松地排列和组织表格&#xff0c;从而简化ER图的可视化显示。 添加了使用两种身份验证方法创建到远程服务器的SSH连接的功能&#xff1a;密码身…