Selenium02

1:引入Unittest

import unittest
  • 自定义的测试用例类需要从unittest.TestCase继承
  • 测试用例的方法名用test开头
  • 执行unittest.main()方法启动程序
#前置方法setUp(self), 在每一个测试用例前执行
def setUp(self):
	print("---start---")
#后置方法tearDown(self),在每一个测试用例后执行
def tearDown(self):
	print("---end---")
#类前置方法setUpClass(cls),在所有测试用例前执行,并且只执行一次
@classmethod
def setUpClass(cls):
    print("---begin---")
#类后置方法tearDownClass(cls),在所有测试用例后执行,并且只执行一次
@classmethod
def tearDownClass(cls):
    print('---over---')

2:PO模式

  • Page Object页面对象,POM(page object model)分层思想,PO模式
  • 基础页面层:对于WebDriver中的API进行二次封装
  • 页面层:继承基础页面层,按照不同的功能编写不同的page
  • Test用例层:实例化页面层对象,引入unittest进行单元测试,包含数据导入,断言,异常处理,日志
  • Util工具类:封装读取Excel数据操作,写日志,生成测试报告,发送邮件等公用方法
    在这里插入图片描述

3:获取Excel数据

依赖:

pip install openpyxl
#获取excel内容
#工作簿,workbook
#工作表,worksheet
#单元行,row
#单元格,cell
    @staticmethod
    def get_excel(bookname,sheetname):
        workbook=openpyxl.load_workbook(bookname)
        worksheet=workbook[sheetname]
        result=[]
        for row in worksheet:
            t=[]
            for cell in row:
                t.append(cell.value)
            result.append(tuple(t))
        #返回内容,不包含数据说明行
        return result[1:]

参数化模块:写在单元测试上,通过Util的方法从数据库导入数据

@parameterized.expand(
        Util.get_excel("路径","SheetName")
    )

4:生成日志

 #日志
    @staticmethod
    def get_log(filename,level=logging.DEBUG):
        # 创建日志对象
        logger = logging.getLogger()
        #设置日志等级
        logger.setLevel(level)
        # 设置日志格式
        formatter = logging.Formatter('[%(asctime)s-%(levelname)s-%(message)s-%(filename)s-%(lineno)s]')
        # 创建文件处理器对象 设置文件名,写策略,编码格式
        fh = logging.FileHandler(filename, mode='a', encoding='utf-8')
        #设置输出格式
        fh.setFormatter(formatter)
        #添加文件处理器对象
        logger.addHandler(fh)
        #返回日志对象
        return logger

在单元测试中的setUpClass方法中创建Logger对象,在关键步骤处进行日志输出

日志级别:

CRITICAL: 'CRITICAL',#致命
    ERROR: 'ERROR',#错误
    WARNING: 'WARNING',#警告
    INFO: 'INFO',#信息
    DEBUG: 'DEBUG',#调试
    NOTSET: 'NOTSET',#不设置
cls.logger = Util.get_log("生成日志存放路径", "日志级别")

#输出日志内容
self.logger.info('添加任务列表成功')

BasePage封装的截图功能:

#封装截图
    def screen_shot(self,path):
        dt = datetime.now()
        timestamp = dt.strftime('%Y-%m-%d %H-%M-%S')
        self.driver.save_screenshot(f"{path}/{timestamp}.png")

5:生成报告且发送邮件

 #邮件
    @staticmethod
    //文件名 发送者 邮箱服务密码 接收者
    def send_email(filename,sender,code,receiver):
        server = 'smtp.163.com'
        port = 25
        mail = MIMEMultipart()
        mail['from'] = sender
        mail['to'] = receiver
        mail['subject'] = '主题'
        with open(filename, 'rb')as file:
            report = file.read()
        attachment = MIMEText(report, 'base64', 'utf-8')
        attachment['Content-Type'] = 'application/octet-stream'
        attachment['Content-Disposition'] = 'attachment;filename=%s' % filename.split('\\')[-1]
        mail.attach(attachment)
        content = """
        <p>&nbsp;&nbsp;&nbsp;&nbsp;主体内容,HTML格式!</p>
        """
        body = MIMEText(content, 'html', 'utf-8')
        mail.attach(body)
        smtp = smtplib.SMTP()
        smtp.connect(server, port)
        smtp.login(sender, code)
        smtp.sendmail(sender, receiver.split(';'), mail.as_string())
        smtp.close()
        print('邮件发送完毕')

runner中生成报告,且在runner中跑所有自动化单元测试脚本:

	sender = '发送邮箱'
    code = '邮箱服务密码'
    receiver = '收件人1;收件人2'
 def run_self(self):
        suite=unittest.TestSuite()
        suite.addTests(unittest.TestLoader().discover(start_dir='自动化脚本路径', pattern='自动化脚本完整名称'))
        dt=datetime.now()
        timestamp=dt.strftime('%Y-%m-%d %H-%M-%S')
        #生成报告的路径和名字
        filename=f'路径/名称-{timestamp}.html'
        report=open(f'{filename}',mode='wb')
        runner=HTMLTestRunner(stream=report,title='测试报告标题',description=r'测试报告描述')
        runner.run(suite)
        Util.send_email(f'{filename}', TestRunner.sender, TestRunner.code, TestRunner.receiver)

6:异常处理

出现断言失败或其他错误时抛出异常,异常信息不在代码中print显示,在测试报告中查看

  • Pass:测试通过(没有异常)

  • Fail:断言失败(AssertionError)

  • Error:断言以外的其他错误(出了AssertionError以外的异常类型)

except AssertionError as e:
    self.logger.error(f'断言失败,原因是{e}')
except Exception as e1:
    self.logger.error(f'失败,其它错误{e1}')

7:封装的BasePage

"""
基础页面类,对webdriver的API进行二次封装
"""
from datetime import datetime

from selenium import webdriver
from selenium.webdriver.common.by import By
from time import sleep
from selenium.webdriver.support.select import Select


class BasePage():

    #初始化方法,创建浏览器对象
    def __init__(self, browser='chrome'):
        # 根据参数browser,创建相应的浏览器对象
        if browser == 'chrome':
            self.driver = webdriver.Chrome()
        elif browser == 'firefox':
            self.driver = webdriver.Firefox()
        elif browser == 'safari':
            self.driver = webdriver.Safari()
        elif browser == 'ie':
            self.driver = webdriver.Ie()
        elif browser == 'opera':
            self.driver = webdriver.Opera()
        elif browser == 'edge':
            self.driver = webdriver.Edge()
        else:
            self.driver = webdriver.Chrome()

    #退出浏览器
    def quit_self(self):
        sleep(5)
        self.driver.quit()

    #关闭浏览器
    def close_self(self):
        sleep(5)
        self.driver.close()

    # 打开指定页面并最大化窗口,设置隐式等待时长
    def open(self, url):
        self.driver.get(url)

    # 将定位方式及其值封装为元组
    def get_locator(self, by, value):
        locator = ()
        if by == 'id' or by == 'i':
            locator = (By.ID, value)
        elif by == 'name' or by == 'n':
            locator = (By.NAME, value)
        elif by == 'class_name' or by == 'c':
            locator = (By.CLASS_NAME, value)
        elif by == 'tag_name' or by == 't':
            locator = (By.TAG_NAME, value)
        elif by == 'link_text' or by == 'l':
            locator = (By.LINK_TEXT, value)
        elif by == 'partial_link_text' or by == 'p':
            locator = (By.PARTIAL_LINK_TEXT, value)
        elif by == 'css_selector' or by == 'css':
            locator = (By.CSS_SELECTOR, value)
        elif by == 'xpath' or by == 'x':
            locator = (By.XPATH, value)
        else:
            locator = (By.ID, value)
        return locator

    # 定位单个元素(含等待逻辑)
    def locate_element(self, by, value, poll_frequency = 0.2, timeout = 5):
        locator = self.get_locator(by, value)
        # 最大询问次数
        n = timeout / poll_frequency
        while n > 0:
            try:
                # 拆包,如果定位到元素将其返回
                element = self.driver.find_element(locator[0], locator[1])
                return element
            except Exception:
                # 定位不到,在异常捕获中让程序睡眠0.2秒,修改n的值,继续执行while循环
                sleep(poll_frequency)
                n = n - 1
        # 超过最大询问次数还未定位到元素,返回None
        return None

    # 定位多个元素(含等待逻辑)
    def locate_elements(self, by, value, poll_frequency=0.2, timeout=5):
        locator = self.get_locator(by, value)
        elements = []
        # 最大询问次数
        n = timeout / poll_frequency
        while n > 0:
            # 定位多个元素
            elements = self.driver.find_elements(*locator)
            # 定位的多个元素不为空
            if elements:
                return elements
            # 定位的多个元素为空,程序睡眠0.2秒,继续循环定位元素
            sleep(poll_frequency)
            n -= 1
        return elements

    # 封装进入frame
    def switch_to_frame(self, by, value):
        iframe1 = self.locate_element(by,value)
        self.driver.switch_to.frame(iframe1)

    #封装退出frame
    def switch_to_parent(self):
        self.driver.switch_to.parent_frame()

    # 封装通过索引选择下拉项
    def select_by_index_self(self, by, value, index):
        select = self.locate_element(by, value)
        Select(select).select_by_index(index)

    # 封装通过value选择下拉项
    def select_by_value_self(self, by, value, select_value):
        select = self.locate_element(by, value)
        Select(select).select_by_value(select_value)

    # 封装通过文本选择下拉项
    def select_by_visible_text_self(self, by, value, text):
        select = self.locate_element(by, value)
        Select(select).select_by_visible_text(text)

    #封装截图
    def screen_shot(self,path):
        dt = datetime.now()
        timestamp = dt.strftime('%Y-%m-%d %H-%M-%S')
        self.driver.save_screenshot(f"{path}/{timestamp}.png")
	
	#清空文本内容
    def clean_text(self,by, value):
        text=self.locate_element(by,value)
        text.clear()
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值