Python自动化测试系列[v1.0.0][高效自动化设计]

news2024/9/21 11:00:36

Python多线程应用于自动化测试

将多线程在测试巧妙地应用,确实会带来很多好处,并且这是充分利用机器资源执行高效率测试很好的方式

# -*- coding: utf-8 -*-
import threading
from time import ctime
import time
from selenium import webdriver


def test_search(browser, word):
    print("Start search at: %s\n" % ctime())
    print("Browser is: %s\n" % browser)
    if browser == 'ie':
        browser_driver = webdriver.Ie()
    elif browser == 'chrome':
        browser_driver = webdriver.Chrome()
    elif browser != 'ie' and browser != 'chrome':
        print("browser 参数非'ie 或 chrome'启动Fiefox")
        browser_driver = webdriver.Firefox()

    browser_driver.get("http://www.baidu.com")
    browser_driver.find_element_by_id("kw").send_keys(word)
    browser_driver.find_element_by_id("su").click()
    time.sleep(3)
    browser_driver.quit()


if __name__ == '__main__':
    dicts = {'chrome':'__davieyang__','ie':'davieyang','davieyang':'davieyang__'}
    threads = []
    for browser, word in dicts.items():
        t = threading.Thread(target = test_search, args=(browser, word))
        threads.append(t)
    for t in range(len(dicts)):
        threads[t].start()
    for t in range(len(dicts)):
        threads[t].join()
# -*- coding: utf-8 -*-
from selenium import webdriver
from time import sleep
from time import ctime
import multiprocessing


def start_browser(browser, time):
    if browser == "chrome":
        print("starting chrome browser now! %s" % ctime())  # 控制台打印当前时间 
        chrome_driver = webdriver.Chrome()
        chrome_driver.get("http://www.baidu.com")
        sleep(time)
        chrome_driver.quit()
    elif browser == "firefox":
        print("starting firefox browser now! %s" % ctime())  # 控制台打印当前时间
        fire_driver = webdriver.Firefox()
        fire_driver.get("http://www.baidu.com")
        sleep(time)
        fire_driver.quit()
    else: 
        print("starting ie browser now! %s" %ctime())  # 控制台打印当前时间
        ie_driver = webdriver.Ie()
        ie_driver.get("http://www.baidu.com")
        sleep(time)
        ie_driver.quit()


#  定义字典参数        
browser_dict = {"chrome": 3, "firefox": 4}
#  定义空List用于存储进程
start_browser_processing = []
#  循环字典Key-Value,创建进程并加入到List中
for browser, time in browser_dict.items():
    processing_browser = multiprocessing.Process(target = start_browser, args = (browser, time))
    start_browser_processing.append(processing_browser)

if __name__ == '__main__':
    for processing_browser in range(len(browser_dict)):
        start_browser_processing[processing_browser].start()
    for processing_browser in range(len(browser_dict)):
        start_browser_processing[processing_browser].join()
    print(u"全部结束 %s" % ctime())

PO设计模式I

当我们以脚本的形式编写了大量的自动化测试代码后,很容易发现代码可读性太差了、任何一个测试脚本几乎毫无扩展能力或者说扩展起来只能修改边边角角、一旦被测系统的UI层发生变化对于测试代码的修改来说简直就是灾难性的,整个自动化工程几乎毫无结构可言,当面临这些问题的时候实际上已经失去了一部分自动化测试原有的职能

任何自动化测试团队在开展自动化测试这项活动的之前,必须考虑的是这项活动的ROI,自动化测试的本职是解放人力,基于前边所述的常见情况不仅仅其ROI非常低,也违背了自动化的初衷

基于这个大背景下,常规的自动化测试活动必须引入PO模式,它是一种自动化测试的设计模式,也是一种解耦的思想即:以页面为单位,将页面中的控件及控件的动作逐一提炼,从而在测试脚本中可以直接使用,其最终目的是使得元素定位表达式``页面对象``测试代码三者分离

而分离后的测试代码,具有极高的可复用性、可读性,可维护性,可扩展性,而这像极了面向对象思想更像极了Java里Spring的MVC模式和Django的MTV模式

定义基本页面类

在自动化测试活动中,每个页面都有其独特的地方,每个月面有都与其共性,为了达到PO模式的目的,首先需要考虑的是每个月面的共性,第一项需要做的就是定义页面的基本特性及活动,它是所有页面类的基类,是独立于所有实际页面之外的

实例代码

# encoding = utf-8
from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep


class Page():
    """
    基础类,仅用于定义一些页面常规内容及方法
    后续各个页面类继承该类实现各自页面的特别内容及方法
    """
    login_url = 'http://mail.163.com'  # 定义基类参数默认值,当调用时未提供该参数时使用

    def __init__(self, driver, base_url=login_url):
        self.base_url = base_url
        self.driver = driver
        self.timeout = 30

    def target_page(self):
        return self.driver.current_url == self.base_url  #  判断当前打开的url与参数给的url是否一致

    def open(self, url):
    	"""打开页面"""
        url = self.base_url
        self.driver.get(url)
        print(self.driver.current_url)
        
    def find_element(self, *loc):
        return self.driver.find_element(*loc)

定义具体页面类

定义了基本页面类,接下来便是具体到每个页面,因为每个也面都有不同,定义具体页面类也是定义其不同,但凡有相同的都应该抽象到基本页面类中去定义

class LoginPage(Page):
    """
    登陆页面,页面对象类
    """
    url = '/'
    """
    此处我们暂时称页面元素为对象,虽然本代码并非那么像对象,后续的框架中我们更高度的封装它便是个可操作的对象
    """
    username_loc = (By.NAME, "email")  # 页面控件对象:输入用户名的input控件
    password_loc = (By.NAME, "password")  # 页面控件对象:输入密码的input控件
    submit_loc = (By.ID, "dologin")  # 页面控件对象:登陆按钮的button控件

    """
    为每个页面元素对象封装其相对应的方法
    """
    def input_username(self, username):
        self.find_element(*self.username_loc).send_keys(username)  # 输入用户名

    def input_password(self, password):
        self.find_element(*self.password_loc).send_keys(password)  # 输入密码

    def click_submitbutton(self):
        self.find_element(*self.submit_loc).click()  # 点击登陆按钮


def user_login(driver, username, password):
    login_page = LoginPage(driver)
    login_page.open()
    sleep(5)
    driver.switch_to.frame(driver.find_element_by_xpath("//*[@id='loginDiv']/iframe"))
    login_page.input_username(username)
    sleep(3)
    login_page.input_password(password)
    sleep(3)
    login_page.click_submitbutton()

编写测试脚本

定义基本页面类是为了更快速的定义具体页面类,使得页面对象的共性可以复用,减少测试代码量;定义具体页面类实际上是扩展了基本页面类,相对于基本页面类而言它是独特的页面类;之后,便可以轻松的编写自动化测试脚本,脚本内容也变得简洁而清晰

def login_main163():
    try:
        driver = webdriver.Chrome()
        username = 'xxxxxx'  # 登陆邮箱需要的真实账号
        password = 'xxxxxx'  # 登陆邮箱需要的真实密码
        user_login(driver, username, password)  # 调用前面封装好的user_login方法
        sleep(3)  #  等待3秒
        driver.switch_to.default_content()  # 切换出iframe
        assert_string = driver.find_element_by_xpath("/html/body/div[1]/nav/div[1]/ul/li[1]/span[2]").text
        print(assert_string)
        assert (assert_string == '收 信')  # 断言关键字
    finally:
        driver.quit()  # 关闭浏览器窗口


if __name__ == '__main__':
    main()

PO设计模式II

任何自动化测试团队在开展自动化测试这项活动的之前,必须考虑的是这项活动的ROI,自动化测试的本职是解放人力,基于前边所述的常见情况不仅仅其ROI非常低,也违背了自动化的初衷

基于这个大背景下,常规的自动化测试活动必须引入PO模式,它是一种自动化测试的设计模式,也是一种解耦的思想即:以页面为单位,将页面中的控件及控件的动作逐一提炼,从而在测试脚本中可以直接使用,其最终目的是使得元素定位表达式 页面对象 测试代码三者分离

而分离后的测试代码,具有极高的可复用性、可读性,可维护性,可扩展性,而这像极了面向对象思想更像极了Java里Spring的MVC模式和Django的MTV模式

定义页面元素

自动化测试一切的根源都来自于页面元素,简单的说自动化测试就是让页面上的控件自己完成它的活动,自动化测试代码要控制这些控件,就首先要获取这些控件的位置,这里讲的不是元素定位的那些方式,而是应该如何处理这些元素定位表达式使其达到分离的效果

在自动化测试工程中新建一个诸如loginpage.ini的属性文件,当然这个文件最好是以页面为单位,每个页面独立分离,然后以控件名=定位方式>定位表达式的形式定义页面每个控件

[leadscloud_login]
input_user_name = xpath>//*[@id='main']/div/div[2]/div[2]/div[2]/div/form/div[1]/div/div/input
input_user_password = xpath>//*[@id='main']/div/div[2]/div[2]/div[2]/div/form/div[2]/div/div[1]/input
button_login = xpath>//*[@id='main']/div/div[2]/div[2]/div[2]/div/form/div[3]/div/button

公共类方法

定义公共类方法,用于解析前面的页面元素,获取元素定位,并返回页面元素对象

"""
用于解析配置文件,并获取页面元素定位表达式
"""
# -*- coding: utf-8 -*-
# @Time: 2019/2/26 11:43
# @Author : Yang DaWei
# @Project : LeadsCloudAutomation
# @FileName: ParseElementLocator.py
from configparser import ConfigParser
from time import sleep
from selenium.webdriver.support.wait import WebDriverWait


class ParseConfigFile:
    """
    初始化解析文件类
    """
    def __init__(self, driver, page_element_locator):
        self.driver = driver
        self.cf = ConfigParser()
        self.cf.read(page_element_locator, encoding='utf-8')

    def get_items_section(self, section_name):
        """
        获取配置文件中指定section下的所有option_name键值对,并以字典类型返回给调用者
        注意:使用self.cf.items(sectionName)此种方法获取到
        配置文件中的options内容均被转换成小写,如loginPage.frame将被转换成loginpage.frame
        """
        options_dict = dict(self.cf.items(section_name))
        return options_dict

    def get_option_value(self, section_name, option_name):
        """
        获取指定section下的指定option的值
        """
        value = self.cf.get(section_name, option_name)
        return value

    def get_element_location(self, section_name, option_name, timeout):
        """
        获取页面元素定位表达式,并以元素对象的形式返回给调用者
        :param section_name:
        :param option_name:
        :param timeout:
        :return:
        """
        driver = self.driver
        location = self.get_option_value(section_name, option_name)
        location_type = location.split(">")[0]
        location_value = location.split(">")[1]
        print("读取到的定位类型为:" + location_type + "\t读取到的定位信息为:" + location_value)
        try:
            element = WebDriverWait(driver, timeout).until(lambda x: x.find_element(by=location_type,
                                                                                    value=location_value))
            return element
        except Exception as e:
            print("定位元素超过" + str(timeout) + "秒,详细异常信息入下:")
            raise e

    def highlight_element(self, driver, element):
        """
        调用JS,用于高亮控件
        :param driver:
        :param element:
        :return:
        """
        driver.execute_script("arguments[0].setAttribute('style', arguments[1]);", element,
                              "background: yellow; border:2px solid red;")


if __name__ == '__main__':
    from selenium import webdriver
    # from Config import VarConfig
    from PageObject.Login_Page import Login_Page
    # locator_file = VarConfig.login_page

    driver = webdriver.Firefox()
    driver.get("http://test.xxxxxx.com/Front-Vue/#/login")
    sleep(5)
    Login_Page(driver).input_user_name().send_keys("yangdawei_10171")
    # ge = ParseConfigFile(driver, locator_file)
    # input_user_name = ge.get_element_location("leadscloud_login", "input_user_name", 5)
    # ge.highlight_element(driver, input_user_name)
    Login_Page(driver).input_user_password().send_keys("yangdawei_10166")
    # input_user_password = ge.get_element_location("leadscloud_login", "input_user_password", 5)
    # ge.highlight_element(driver, input_user_password)
    # input_user_password.send_keys("111111")
    # button_login = ge.get_element_location("leadscloud_login", "button_login", 5)
    # ge.highlight_element(driver, button_login)
    Login_Page(driver).login_button().click()
    driver.quit()

页面元素对象封装

通过公共类方法,读取页面元素定位信息,让后以页面控件为单位封装成可操作的对象

'''用于获取PageElementLocator.ini 中Login页面元素对象'''
# encoding = utf-8
"""
__title__ = ''
__author__ = 'davieyang'
__mtime__ = '2018/4/21'
"""
from Util.GetElements import *
from Util.ParseElementLocator import ParseConfigFile


class LoginPage(object):

    def __init__(self, driver):
        self.driver = driver
        self.parseCF = ParseConfigFile()
        self.loginOptions = self.parseCF.getItemsSection("163mail_login")
        print(self.loginOptions)

    def switchtoframe(self):
        try:
            # 从定位表达式配置文件中读取frame的定位表达式
            locatorExpression = self.loginOptions["loginPage.frame".lower()].split('>')[1]
            self.driver.switch_to.frame(locatorExpression)
        except Exception as e:
            raise e

    def switchtodefaultframe(self):
        try:
            self.driver.switch_to.default_content()
        except Exception as e:
            raise e

    def usernameobj(self):
        try:
            # 从定位表达式配置文件中读取定位用户名如输入框的定位方式和表达式
            locateType, locatorExpression = self.loginOptions["loginPage.username".lower()].split(">")
            # 获取登录页面的用户名输入框页面对象,返回给调用者
            elementobj = get_element(self.driver, locateType, locatorExpression)
            return elementobj
        except Exception as e:
            raise e

    def passwordobj(self):
        try:
            # 从定位表达式配置文件中读取定位密码输入框的定位方式和表达式
            locateType, locatorExpression = self.loginOptions["loginPage.password".lower()].split(">")
            # 获取登录页面的密码输入框页面对象,并返回给调用者
            elementoj = get_element(self.driver, locateType, locatorExpression)
            return elementoj
        except Exception as e:
            raise e

    def loginbutton(self):
        try:
            # 从定位表达式配置文件中读取定位登录按钮的定位方式和表达式
            locateType, locatorExpression = self.loginOptions["loginPage.loginbutton".lower()].split(">")
            # 获取登录页面的登录按钮页面对象,并返回给调用者
            elementobj = get_element(self.driver, locateType, locatorExpression)
            return elementobj
        except Exception as e:
            raise e


if __name__ == '__main__':
    from selenium import webdriver
    import time
    driver = webdriver.Chrome(executable_path="F:\\automation\\webdriver\\chromedriver.exe")
    driver.get("http://mail.163.com")
    time.sleep(5)
    login = LoginPage(driver)
    login.switchtoframe()
    login.usernameobj().send_keys("xxxx")
    login.passwordobj().send_keys("xxxx")
    login.loginbutton().click()
    time.sleep(10)
    login.switchtodefaultframe()
    assert u"未读邮件" in driver.page_source
    driver.quit()

简洁的测试脚本

# -*- coding: utf-8 -*-
# @Time: 2019/3/1 13:40
# @Author : Yang DaWei
# @Project : LeadsCloudAutomation
# @FileName: test_login_page.py
import time
import unittest
from selenium import webdriver
from PageObject.Login_Page import Login_Page

class Test_Login_Page(unittest.TestCase):

    driver = None
    @classmethod
    def setUpClass(cls):
        """ set Up method """
        cls.driver = webdriver.Chrome()
        cls.test_page = ''
        time.sleep(3)

    def tearDown(self):
        """ tear Down method """

    def setUp(self):
        """setUP pass"""

    @classmethod
    def tearDownClass(cls):
        """ tear Down method """
        cls.driver.close()

    def test_login(self):
        self.driver.get("http://admin.xxxxxxx.com/Front-Vue/#/")
        Login_Page(self.driver).input_user_name().send_keys("yangdawei_10171")
        Login_Page(self.driver).input_user_password().send_keys("111111")
        Login_Page(self.driver).login_button().click()
        try:
            self.assertTrue("仪表盘", self.driver.page_source)
            print("断言成功")
        except Exception as e:
            raise e
        time.sleep(10)

关键字驱动

在关键字驱动测试框架中,除了PO模式以及一些常规Action的封装外,一个很重要的内容就是读写EXCEL,在团队中如何让不会写代码的人也可以进行自动化测试? 我们可以将自动化测试用例按一定的规格写到EXCEL中去(如下图所示)
在这里插入图片描述
然后通过代码实现对具备这种规格的EXCEL进行解析,让你的代码获取EXCEL中的步骤,关键字,页面元素定位,操作方式,最后在写入执行结果,附上异常截图即可;团队中不会写代码的人居多,改改Excel执行也可以实现自动化测试

此处在初始化类的时候定义了两个颜色放进字典中,之后会当做参数传给写EXCEL的函数,当测试用例执行通过 用绿色字体标注pass,当执行失败的时候用红色字体标注failed

解析关键字

具体实现代码如下

# 用于实现读取Excel数据文件代码封装
# encoding = utf-8
"""
__project__ = 'KeyDri'
__author__ = 'davieyang'
__mtime__ = '2018/4/21'
"""
import openpyxl
from openpyxl.styles import Border, Side, Font
import time
 
 
class ParseExcel(object):
 
    def __init__(self):
        self.workBook = None
        self.excelFile = None
        self.font = Font(color=None)
        self.RGBDict = {'red': 'FFFF3030', 'green': 'FF008B00'}
 
    def loadWorkBook(self, excelPathAndName):
        # 将Excel加载到内存,并获取其workbook对象
        try:
            self.workBook = openpyxl.load_workbook(excelPathAndName)
        except Exception as e:
            raise e
        self.excelFile = excelPathAndName
        return self.workBook
 
    def getSheetByName(self, sheetName):
        # 根据sheet名获取该sheet对象
        try:
            # sheet = self.workBook.get_sheet_by_name(sheetName)
            sheet = self.workBook[sheetName]
            return sheet
        except Exception as e:
            raise e
 
    def getSheetByIndex(self, sheetIndex):
        # 根据sheet的索引号获取该sheet对象
        try:
            # sheetname = self.workBook.get_sheet_names()[sheetIndex]
            sheetname = self.workBook.sheetnames[sheetIndex]
        except Exception as e:
            raise e
        # sheet = self.workBook.get_sheet_by_name(sheetname)
        sheet = self.workBook[sheetname]
        return sheet
 
    def getRowsNumber(self, sheet):
        # 获取sheet中有数据区域的结束行号
        return sheet.max_row
 
    def getColsNumber(self, sheet):
        # 获取sheet中有数据区域的结束列号
        return sheet.max_column
 
    def getStartRowNumber(self, sheet):
        # 获取sheet中有数据区域的开始的行号
        return sheet.min_row
 
    def getStartColNumber(self, sheet):
        # 获取sheet中有数据区域的开始的列号
        return sheet.min_column
 
    def getRow(self, sheet, rowNo):
        # 获取sheet中某一行,返回的是这一行所有数据内容组成的tuple
        # 下标从1开始,sheet.rows[1]表示第一行
        try:
            # return sheet.rows[rowNo - 1] 因为sheet.rows是生成器类型,不能使用索引
            # 转换成list之后再使用索引,list(sheet.rows)[2]这样就获取到第二行的tuple对象。
            return list(sheet.rows)[rowNo - 1]
        except Exception as e:
            raise e
 
    def getCol(self, sheet, colNo):
        # 获取sheet中某一列,返回的是这一列所有数据内容组成的tuple
        # 下标从1开始,sheet.columns[1]表示第一列
        try:
            return list(sheet.columns)[colNo - 1]
        except Exception as e:
            raise e
 
    def getCellOfValue(self, sheet, coordinate = None, rowNo = None, colNo = None):
        # 根据单元格所在的位置索引获取该单元格中的值,下标从1开始
        # sheet.cell(row = 1, column = 1).value,表示excel中的第一行第一列的值
        if coordinate is not None:
            try:
                return sheet.cell(coordinate=coordinate).value
            except Exception as e:
                raise e
        elif coordinate is None and rowNo is not None and colNo is not None:
            try:
                return sheet.cell(row=rowNo, column=colNo).value
            except Exception as e:
                raise e
        else:
            raise Exception("Insufficient Coordinates of cell!")
 
    def getCellOfObject(self, sheet, coordinate = None, rowNo = None, colNo = None):
        # 获取某个单元格对象,可以根据单元格所在的位置的数字索引,也可以直接根据Excel中单元格的编码及坐标
        # 如getCellOfObject(sheet, coordinate='A1) or getCellOfObject(sheet, rowNo = 1, colNo = 2)
 
        if coordinate is not None:
            try:
                return sheet.cell(coordinate=coordinate)
            except Exception as e:
                raise e
        elif coordinate is None and rowNo is not None and colNo is not None:
            try:
                return sheet.cell(row=rowNo, column=colNo)
            except Exception as e:
                raise e
        else:
            raise Exception("Insufficient Coordinates of cell!")
 
    def writeCell(self, sheet, content, coordinate = None, rowNo = None, colNo = None, style=None):
        # 根据单元格在Excel中的编码坐标或者数字索引坐标向单元格中写入数据,下标从1开始
        # 参数style表示字体的颜色的名字,如red,green
        if coordinate is not None:
            try:
                sheet.cell(coordinate=coordinate).value = content
                if style is not None:
                    sheet.cell(coordinate=coordinate).font = Font(color=self.RGBDict[style])
                self.workBook.save(self.excelFile)
            except Exception as e:
                raise e
        elif coordinate is None and rowNo is not None and colNo is not None:
            try:
                sheet.cell(row=rowNo, column=colNo).value = content
                if style is not None:
                    sheet.cell(row=rowNo, column=colNo).font = Font(color=self.RGBDict[style])
                self.workBook.save(self.excelFile)
            except Exception as e:
                raise e
        else:
            raise Exception("Insufficient Coordinates of cell!")
 
    def writeCellCurrentTime(self, sheet, coordinate = None, rowNo = None, colNo = None):
        # 写入当前时间,下标从1开始
        now = int(time.time())  # 显示为时间戳
        timeArray = time.localtime(now)
        currentTime = time.strftime("%Y-%m-%d %H:%M:%S", timeArray)
        if coordinate is not None:
            try:
                sheet.cell(coordinate=coordinate).value = currentTime
                self.workBook.save(self.excelFile)
            except Exception as e:
                raise e
        elif coordinate is None and rowNo is not None and colNo is not None:
            try:
                sheet.cell(row=rowNo, column=colNo).value = currentTime
                self.workBook.save(self.excelFile)
            except Exception as e:
                raise e
 
 
if __name__ == "__main__":
    from Configurations.VarConfig import dataFilePath163
    pe = ParseExcel()
    pe.loadWorkBook(dataFilePath163)
    print("通过名称获取sheet对象名字:")
    pe.getSheetByName(u"联系人")
    print("通过Index序号获取sheet对象的名字")
    pe.getSheetByIndex(0)
    sheet = pe.getSheetByIndex(0)
    print(type(sheet))
    print(pe.getRowsNumber(sheet))
    print(pe.getColsNumber(sheet))
    cols = pe.getCol(sheet, 1)
    for i in cols:
        print(i.value)
    # 获取第一行第一列单元格内容
    print(pe.getCellOfValue(sheet, rowNo=1, colNo=1))
    pe.writeCell(sheet, u'中国北京', rowNo=11, colNo=11, style='red')
    pe.writeCellCurrentTime(sheet, rowNo=10, colNo=11)

解析Excel实际上方法不一


# encoding = utf-8
"""
__title__ = ''
__author__ = 'davieyang'
__mtime__ = '2018/4/21'
"""
import xlrd


class ExcelUtil():
    def __init__(self, excelPath, sheetName):
        self.data = xlrd.open_workbook(excelPath)
        self.table = self.data.sheet_by_name(sheetName)
        # 获取第一行作为key值
        self.keys = self.table.row_values(0)
        # 获取总行数
        self.rowNum = self.table.nrows
        # 获取总列数
        self.colNum = self.table.ncols

    def dict_data(self):
        if self.rowNum <= 1:
            print("总行数小于1")
        else:
            r = []
            j = 1
            for i in range(self.rowNum -1):
                s = {}
                # 从第二行取对应values值
                values = self.table.row_values(j)
                for x in range(self.colNum):
                    s[self.keys[x]] = values[x]
                r.append(s)
                j += 1
            return r


if __name__ == '__main__':
    excelPath = u"F:\\seleniumWithPython\\TestData\\163邮箱联系人.xlsx"
    sheetName = u"163账号"
    data = ExcelUtil(excelPath, sheetName)
    print(data.dict_data())

# 打开exlce表格,参数是文件路径
# data = xlrd.open_workbook('test.xlsx')

# table = data.sheets()[0]           #  通过索引顺序获取
# table = data.sheet_by_index(0)     #  通过索引顺序获取
# table = data.sheet_by_name(u'Sheet1')  # 通过名称获取

# nrows = table.nrows  # 获取总行数
# ncols = table.ncols  # 获取总列数

# 获取一行或一列的值,参数是第几行
#  print table.row_values(0)  # 获取第一行值
#  print table.col_values(0)  # 获取第一列值

关键字驱动测试代码

# 用于编写具体的测试逻辑代码
# encoding = utf-8
"""
__title__ = ''
__author__ = 'davieyang'
__mtime__ = '2018/4/21'
"""
from Util.GetElements import *
from Util.KeyBoardOperations import Keyboardkeys
from Util.ClipboardUtil import Clipboard
from Util.SmartWaitElements import WaitUtil
from selenium import webdriver
from selenium.webdriver.common.keys import Keys
from KeyDrivenMode.Actions.PageAction import *
import time

from KeyDrivenMode.Actions.PageAction import *
from Util.ParseExcelFile import ParseExcel
from Configurations.VarConfig import *
import time
import traceback

excelObj = ParseExcel()
excelObj.loadWorkBook(dataFilePath126)


def writeTestResult(sheetObj, rowNo, colNo, testResult, errorInfo = None, picPath = None):
    # 测试通过结果信息为绿色,失败为红色
    colorDict = {"pass": "green", "fail": "red"}
    # 因为测试用例工作表和用例步骤工作表中都有测试执行时间和测试结果列,定义此字典对象是为了区分具体应该写哪个工作表

    colDict = {"testCase": [testCase_runTime, testCase_testResult], "caseStep": [testStep_runTime, testStep_testResult]}
    try:
        # 在测试步骤工作表中,写入测试时间
        excelObj.writeCellCurrentTime(sheetObj, rowNo=rowNo, colNo=colDict[colNo][0])
        # 在测试步骤工作表中,写入测试结果
        excelObj.writeCell(sheetObj, content=testResult, rowNo=rowNo, colNo=colDict[colNo][1])
        if errorInfo and picPath:
            # 在测试步骤工作表中,写入异常信息
            excelObj.writeCell(sheetObj, content=errorInfo, rowNo=rowNo, colNo=testStep_errorInfo)
            # 在测试步骤工作表中,写入异常截图路径
            excelObj.writeCell(sheetObj, content=picPath, rowNo=rowNo, colNo=testStep_errorPic)
        else:
            # 在测试步骤工作表中,清空异常信息单元格
            excelObj.writeCell(sheetObj, content="", rowNo=rowNo, colNo=testStep_errorInfo)
            # 在测试步骤工作表中,清空异常截图路径单元格
            excelObj.writeCell(sheetObj, content="", rowNo=rowNo, colNo=testStep_errorPic)
    except Exception as e:
        print(u"写excel出错", traceback.print_exc())


def TestSendMailWithAttachment():
    try:
        # 根据Excel文件中的sheet名获取sheet对象
        caseSheet = excelObj.getSheetByName(u"测试用例")
        # 获取测试用例sheet中是否执行列对象
        isExeuteColumn = excelObj.getCol(caseSheet, testCase_isExecute)
        # 记录执行成功的测试用例个数
        successfulCase = 0
        # 记录需要执行的用力个数
        requiredCase = 0
        for idx, i in enumerate(isExeuteColumn[1:]):
            # 因为用例sheet中的第一行为标题行,无需执行
            # print(i.value)
            # 循环遍历“测试用例”表中的测试用例,执行被设置为执行的用例
            if i.value.lower() == "y":
                requiredCase += 1
                # 获取“测试用例”表中第idx+2行的数据
                caseRow = excelObj.getRow(caseSheet, idx +2)
                # 获取idx+2行的“步骤sheet”单元格内容
                caseStepSheetName = caseRow[testCase_testStepSheetName - 1].value
                # print(caseStepSheetName)

                # 根据用例步骤名获取步骤sheet对象
                stepSheet = excelObj.getSheetByName(caseStepSheetName)
                # 获取步骤sheet中步骤数
                stepNum = excelObj.getRowsNumber(stepSheet)
                # print(stepNum)
                # 记录测试用例i的步骤成功数
                successfulSteps = 0
                print(u"开始执行用例%s" % list(caseRow)[testCase_testCaseName - 1].value)
                for step in range(2, stepNum + 1):
                    # 因为步骤sheet中的第一行为标题行,无需执行
                    # 获取步骤sheet中的第step行对象
                    stepRow = excelObj.getRow(stepSheet, step)
                    # 获取关键字作为调用的函数名
                    keyWord = stepRow[testStep_keyWords - 1].value
                    # 获取操作元素定位方式作为调用的函数的参数
                    locationType = stepRow[testStep_locationType - 1].value
                    # 获取操作元素定位表达式作为调用函数的参数
                    locatorExpression = stepRow[testStep_locatorExpression - 1].value
                    # 获取操作值作为调用函数的参数
                    operateValue = stepRow[testStep_operateValue - 1].value
                    # 将操作值为数字类型的数据转换成字符串类型,方便字符串拼接
                    if isinstance(operateValue, int):
                        operateValue = str(operateValue)
                    print(keyWord, locationType, locatorExpression, operateValue)
                    expressionStr = ""
                    # 构造需要执行的python语句
                    # 对应的是PageAction.py文件中的页面动作函数调用的字符串表示
                    if keyWord and operateValue and locationType is None and locatorExpression is None:
                        expressionStr = keyWord.strip() + "(u'" +operateValue+"')"
                    elif keyWord and operateValue is None and locationType is None and locatorExpression is None:
                        expressionStr = keyWord.strip() + str()
                    elif keyWord and locationType and operateValue and locatorExpression is None:
                        expressionStr = keyWord.strip() + "('" + locationType.strip() + "', u'" + operateValue + "')"
                    elif keyWord and locationType and locatorExpression and operateValue:
                        expressionStr = keyWord.strip() + "('" + locationType.strip() + "', '" + locatorExpression.replace("'", '"').strip() + "', u'" + operateValue + "')"
                    elif keyWord and locationType and locatorExpression and operateValue is None:
                        expressionStr = keyWord.strip() + "('" + locationType.strip() + "', '" + locatorExpression.replace("'", '"').strip() + "')"
                    print(expressionStr)
                    try:
                        # 通过eval函数,将拼接的页面动作函数调用的字符串表示
                        # 当成有效的Python表达式执行,从而执行测试步骤的sheet中
                        # 关键字在PageAction.py文件中对应的映射方法
                        # 来完成对页面元素的操作
                        eval(expressionStr)
                        # 在测试执行时间列写入执行时间
                        excelObj.writeCellCurrentTime(stepSheet, rowNo=step, colNo=testStep_runTime)
                    except Exception as e:
                        # 截取异常屏幕图片
                        capturePic = capture_screen()
                        # 获取详细的异常堆栈信息
                        errorInfo = traceback.format_exc()
                        # 在测试步骤sheet中写入失败信息
                        writeTestResult(stepSheet, step, "caseStep", "faild", errorInfo, capturePic)
                        print(u"步骤 %s 执行失败!" % list(stepRow)[testStep_testStepDescribe - 1].value)
                    else:
                        # 在测试步骤sheet中写入成功信息
                        writeTestResult(stepSheet, step, "caseStep", "pass")
                        # 每成功一步successfulSteps变量自增1
                        successfulSteps += 1
                        print(u"步骤 %s 执行成功!" % list(stepRow)[testStep_testStepDescribe - 1].value)
                if successfulSteps == stepNum - 1:
                    # 当测试用例步骤sheet中所有的步骤都执行成功
                    # 才认为此测试用例执行通过,然后将成功信息写入
                    # 测试用例工作表中,否则写入失败信息
                    writeTestResult(caseSheet, idx + 2, "testCase", "pass")
                    successfulCase += 1
                else:
                    writeTestResult(caseSheet, idx+2, "testCase", "faild")
        print(u"共%d条用例,%d条需要被执行,本次直行通过%d条." % (len(isExeuteColumn)-1, requiredCase, successfulCase))
    except Exception as e:
        # 打印详细的异常堆栈信息
        print(traceback.print_exc())


if __name__ == "__main__":
    TestSendMailWithAttachment()
    """
    不借用PageAction.py
    # 创建Chrome浏览器实例
    driverchrome = webdriver.Chrome(executable_path=r"F:\automation\webdriver\chromedriver.exe")
    driverchrome.maximize_window()
    driverchrome.get("http://mail.126.com")
    time.sleep(5)
    assert u"126网易免费邮--你的专业电子邮局" in driverchrome.title
    print("access 126 successfully")

    wait = WaitUtil(driverchrome)
    wait.frame_to_be_available_and_switch_to_it("id", "x-URS-iframe")
    username = get_element(driverchrome, "xpath", "//input[@name='email']")
    username.send_keys("davieyang008")
    password = get_element(driverchrome, "xpath", "//input[@name='password']")
    password.send_keys("Ethan005x")
    password.send_keys(Keys.ENTER)
    time.sleep(5)
    assert u"网易邮箱" in driverchrome.title
    print("login successfully")

    element = wait.visibility_element_located("xpath", "//li[@id='_mail_component_70_70']")
    element.click()
    receiver = get_element(driverchrome, "xpath", "//div[contains(@id, '_mail_emailinput')]/input")
    receiver.send_keys("15901281916@163.com")
    subject = get_element(driverchrome, "xpath", "//div[@aria-label = '邮件主题输入框,请输入邮件主题']/input")
    subject.send_keys("new email")
    # 设置剪切板内容
    Clipboard.setText(u"F:\\a.txt")
    # 获取剪切板内容
    Clipboard.getText()
    attachment = get_element(driverchrome, "xpath", "//div[contains(@title, '点击添加附件')]")
    # 单击上传附件链接
    attachment.click()
    time.sleep(3)
    # 在上传附件windows弹窗中黏贴剪切板中的内容
    Keyboardkeys.twoKey('ctrl', 'v')
    # 模拟回车以便加载要上传的附件
    time.sleep(3)
    Keyboardkeys.oneKey('enter')
    # 切换进邮件正文的frame
    wait.frame_to_be_available_and_switch_to_it("xpath", "//iframe[@tabindex=1]")
    body = get_element(driverchrome, "xpath", "/html/body")
    # 输入邮件正文
    body.send_keys("abcabc")
    # 切出邮件正文的frame
    driverchrome.switch_to.default_content()
    get_element(driverchrome, "xpath", "//header//span[text()='发送']").click()
    time.sleep(3)
    assert u"发送成功" in driverchrome.page_source
    print(u"邮件发送成功")
    driverchrome.quit()
    :return:
    """
    """
    借用PageAction.py
    open_browser("chrome")
    maximize_browser()
    visit_url("http://mail.126.com")
    sleep(5)
    assert_string_in_pagesource(u"126网易免费邮--你的专业电子邮局")
    waitFrameToBeAvailableAndSwitchToIt("id", "x-URS-iframe")
    input_string("xpath", "//input[@name='email']", "davieyang008")
    input_string("xpath", "//input[@name='password']", "Ethan005x")
    click("id", "dologin")
    sleep(5)
    assert_title(u"网易邮箱")
    waitVisibilityOfElementLocated("xpath", "//li[@id='_mail_component_70_70']")
    click("xpath", "//li[@id='_mail_component_70_70']")
    input_string("xpath", "//div[contains(@id, '_mail_emailinput')]/input", "15901281916@163.com")
    input_string("xpath", "//div[@aria-label = '邮件主题输入框,请输入邮件主题']/input", "new email")
    click("xpath", "//div[contains(@title, '点击添加附件')]")
    sleep(3)
    paste_string(u"F:\\a.txt")
    press_enter_key()
    waitFrameToBeAvailableAndSwitchToIt("xpath", "//iframe[@tabindex=1]")
    input_string("xpath", "/html/body", "abcdef")
    switch_to_default_content()
    click("xpath", "//header//span[text()='发送']")
    time.sleep(3)
    assert_string_in_pagesource(u"发送成功")
    close_browser()
    """





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

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

相关文章

百度网盘非会员,享受视频倍速

百度网盘会员过期了&#xff0c;看视频不能倍速很难受&#xff0c;下面就是跨过会员机制&#xff0c;享受倍速的方法。 Edge浏览器 在浏览器设置中找到扩展选项 在扩展中搜索视频速度控制 global speed&#xff0c;安装后即可使用

品牌推广必备:软文案例撰写与文案策划全解析!

做品牌推广&#xff0c; 不仅需要有推广渠道&#xff0c;文案的策划也是必不可少的一部分。文案是属于灵魂的部分。 作为一名手工酸奶品牌的创始人&#xff0c;目前全国也复制了100多家门店&#xff0c;这篇文章&#xff0c;详细和大家拆解&#xff0c;文案创作的要点&#xf…

金融科技赋能:加马智能质检系统引领金融机构迈向高效合规新时代

为了保护消费者合法权益、促进市场稳定健康发展&#xff0c;近年来监管机构相继发布了《银行保险机构消费者权益保护管理办法》、《银行业金融机构销售专区录音录像管理暂行规定》、《保险销售行为管理办法》等多项法律法规&#xff0c;对于银行、保险等金融机构的服务、销售行…

神卓互联共享文件使用教程

#文件共享# 文件共享已成为我们日常生活和工作中不可或缺的一部分。它如同一条无形的纽带&#xff0c;将人们紧密地联系在一起&#xff0c;促进了信息的快速传播和交流。 文件共享的魅力在于其打破了地域和时间的限制。无论我们身处世界的哪个角落&#xff0c;只要有网络连接&a…

我们所熟知的meme梗图也可以用AI生成了,老外都玩坏了。

meme梗图不知道大家看到过嘛&#xff1f;相信你们看见下面的图你就会大叫“卧槽”&#xff0c;原来是这种图&#xff0c;我以前经常狂刷不止&#xff0c;太有趣了。 其实meme是一个网络流行语&#xff0c;可译为模因。在大众非学术范围内也可翻译为我们所熟知的“梗”。其中“表…

4个方法帮助你解决RAR解压文件时提示密码错误问题

在日常工作和学习中&#xff0c;我们经常需要处理各种压缩文件&#xff0c;这些文件有时为了保护内容安全&#xff0c;会被设置密码。然而&#xff0c;在解压这些文件时&#xff0c;如果遇到“密码错误”的提示&#xff0c;可能会让人感到十分棘手。今天&#xff0c;我们就来探…

C++规范

一、VS工具集列表&#xff1a; Visual Studio 2008&#xff1a;v90 Visual Studio 2010&#xff1a;v100 Visual Studio 2012&#xff1a;v110 Visual Studio 2013&#xff1a;v120 Visual Studio 2015&#xff1a;v140 &#xff08;v140_xp&#xff09; Visual Studio 2017&a…

Java-Sql注入以及如何解决

sql脚本注入: 如果sql语句使用字符串拼接&#xff0c;可能会出现字符串的拼接&#xff0c;导致sql注入。 #是会先进行预编译&#xff0c;传进来的参数通过占位符填入到已经完成编译的语句中去。

windows 11 + kali wsl二合一配置步骤与踩坑

windows 11 kali wsl二合一配置步骤与踩坑 在前几天的某市攻防演练中&#xff0c;在攻防前期&#xff0c;我的虚拟机经常无缘无故出现断网、卡顿等现象&#xff0c;但找不出原因。 为了不影响后续的这些天的攻防演练&#xff0c;我选择在一个晚上通宵 在我的windows 11系统上…

鼠标录制工具|键鼠轨迹录制,实现自动办公

利用键鼠录制工具录制固定的鼠标点击、键盘输入等操作&#xff0c;实现自动化执行固定操作&#xff0c;节省时间。鼠标录制功能可以录制多步骤的操作&#xff0c;将录制的动作保存并命名&#xff0c;甚至可以编辑操作速度。下面将演示几种生活中常见的案例&#xff0c;详细讲解…

怎么才能选到好的猫咪主食冻干?公认顶尖优秀主食冻干总结

如今&#xff0c;主食冻干市场纷繁多样&#xff0c;质量水平却大相径庭。部分品牌盲目追求高营养值和利润增长&#xff0c;却忽略了猫咪健康饮食的本质需求&#xff0c;导致市场上充斥着以次充好、虚假标注日期等不法行为。更有甚者&#xff0c;部分产品未经权威第三方检测便匆…

E - Tree and Hamilton Path 2

算出所有路径之和2减去树的直径 #include <bits/stdc.h> using namespace std; typedef long long ll; const int N2e610; ll n,ans; ll e[N],h[N],idx,w[N],ne[N],dis[N]; void add(ll a,ll b,ll c){ e[idx]b,ne[idx]h[a],w[idx]c,h[a]idx; } ll c; void dfs(ll u,…

5款好用公司监控软件分享|管理者必看

当今社会&#xff0c;企业数据安全和员工工作效率成为了管理者不可忽视的重要议题。 选择合适的公司监控软件&#xff0c;不仅有助于提升管理效率&#xff0c;还能有效保障企业信息安全。 下面小编将为您分享五款备受好评的公司监控软件&#xff0c;助力管理者更好地管理企业…

前端使用Threejs加载机械臂并控制机械臂跳舞

1. 前言 在我的第一篇博客中,大致讲解了如何使用threejs导入机械臂模型,以及如何让机械臂模型动起来的案例,可以看一下之前的博客前端使用Threejs控制机械臂模型运动 本篇博客主要讲解的是在原来的基础上添加GSAP动画库的应用,可以通过动画,来让机械臂进行指定轨迹位姿的运动…

vue3 学习 之 vue3使用

为什么要学习vue3呢&#xff1f; vue2.0也是现在比较稳定的一个版本&#xff0c;社区还有周边都比较完善&#xff0c;如果不是非必要其实我们不需要着急直接升级到vue3.0; 那为什么还要学习&#xff0c;主要是还是为了了解一下vue3.0相较于2.0的优势和特性&#xff0c;方便之后…

C++20中的基于范围的for循环(range-based for loop)

C11中引入了对基于范围的for循环(range-based for loop)的支持&#xff1a;该循环对一系列值(例如容器中的所有元素)进行操作。代码段如下&#xff1a; const std::vector<int> vec{ 1,2,3,4,5 }; for (const auto& i : vec)std::cout << i << ", …

推荐系统三十六式学习笔记:原理篇.MAB问题18|如何将Bandit算法与协同过滤组合使用

目录 信息茧房COFIBA1.思想2.细节 再谈EE问题总结 荐系统中最经典的算法是协同过滤&#xff0c;其背后的思想简单深刻&#xff0c;在万物互联的今天&#xff0c;协同过滤的威力更加强大。与其说协同过滤是一门技术&#xff0c;不如说是一种方法论&#xff0c;协同过滤生动的诠释…

MySQL 索引你必须知道的那些事

MySQL 索引你必须知道的那些事 一、什么是索引&#xff1f;二、索引相关命令演示三、添加索引的条件四、索引失效的几种情况五、索引背后的数据结构1、概述2、B树3、B树4、如果一个表中有多个索引&#xff08;回表现象&#xff09; 一、什么是索引&#xff1f; 索引是在数据库…

Unity实现安卓App预览图片、Pdf文件和视频的一种解决方案

一、问题背景 最近在开发app项目&#xff0c;其中有个需求就是需要在app软件内显示图片、pdf和视频&#xff0c;一开始想的解决方案是分开实现&#xff0c;也就是用Image组件显示图片&#xff0c;找一个加载pdf的插件和播放视频的插件&#xff0c;转念一想觉得太麻烦了&#x…

StarRocks下载使用说明和基础操作

简介 StarRocks 是一款高性能分析型数据仓库&#xff0c;使用向量化、MPP 架构、CBO、智能物化视图、可实时更新的列式存储引擎等技术实现多维、实时、高并发的数据分析。StarRocks 既支持从各类实时和离线的数据源高效导入数据&#xff0c;也支持直接分析数据湖上各种格式的数…