Selenium Web自动化测试框架实践

2023-10-30

功能实现

  • 自动运行用例
  • 自动生成测试报告
  • 自动断言与截图
  • 自动将最新测试报告发送到指定邮箱
  • 自动生成测试报告
  • 数据,页面元素、测试用例分离
  • 执行日志、分布式执行
  • 配置化文件、元素、数据

实践功能

https://passport.csdn.net/login CSDN登录页面

项目架构

在这里插入图片描述

浏览器driver定义

from common.readFile import ReadFile
from common.logger import Logger
from selenium import webdriver

logger = Logger()

from selenium.webdriver import Remote

class Browser():

    def __init__(self):
        config = ReadFile()
        self.browser = config.readConfig("Browser", "browser")
        self.host = config.readConfig("host","host")
        logger.info("You had select {} host {} browser.".format(self.host,self.browser))

    def driver(self):
        """
        启动浏览器驱动
        :return: 返回浏览器驱动URL
        """
        try:
            # driver = webdriver.Chrome()
            driver = Remote(command_executor='http://' + self.host + '/wd/hub',
                            desired_capabilities={ 'platform': 'ANY',
                                                   'browserName': self.browser,
                                                   'version': "",
                                                   'javascriptEnabled': True
                                                }
                            )
            return driver
        except Exception as msg:
            print("驱动异常-> {0}".format(msg))

用例运行前后的环境准备工作

import unittest
from common.driver import Browser

class StartEnd(unittest.TestCase):
    def setUp(self):
        self.driver = Browser().driver()
        self.driver.implicitly_wait(10)
        self.driver.maximize_window()

    def tearDown(self):
        self.driver.quit()

工具方法模块

主要封装一些公共的方法如:截图,查找最新报告

import time
from selenium import webdriver

import os,sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))

from config import setting

def inser_img(driver):
    # 指定截图存放的根目录路径
    screen_dir = setting.TEST_REPORT + '/imges/'
    rq = time.strftime('%Y%m%d%H%M%S', time.localtime(time.time()))
    screen_name = screen_dir + rq + '.png'
    driver.get_screenshot_as_file(screen_name)
    print('screenshot:' + screen_name)

#查找最新的测试报告
def latest_report(report_dir):
    lists = os.listdir(report_dir)
    lists.sort(key=lambda fn: os.path.getatime(report_dir + '\\' + fn))
    file = os.path.join(report_dir, lists[-1])
    return file

def latest_report_img(report_dir):
    lists = os.listdir(report_dir)
    lists.sort(key=lambda fn: os.path.getatime(report_dir + '\\' + fn))
    file = os.path.join(report_dir, lists[-1])
    return file

Pageobject页面对象封装

基础页面封装类

import time
from selenium import webdriver
from selenium.common.exceptions import NoSuchElementException
from common.logger import Logger
from common.readFile import ReadFile

logger = Logger()

class BasePage():
    "定义一个页面基类,让所有页面都继承这个类,封装一些常用的页面操作方法到这个类"

    def __init__(self, driver):
        self.driver = driver
        config = ReadFile()
        self.baseurl = config.readConfig("BaseUrl", "url")

    def open_url(self, url):
        self.driver.get(self.baseurl + url)

    # 退出浏览器
    def quit_browser(self):
        self.driver.quit()

    # 浏览器前进操作
    def forward(self):
        self.driver.forward()

    # 浏览器后退操作
    def back(self):
        self.driver.back()

    # 隐式等待
    def wait(self, seconds):
        self.driver.implicitly_wait(seconds)

    # 查找元素
    def find_element(self, selector):
        selector_by = selector['find_type']
        selector_value = selector['element_info']

        try:
            if selector_by == 'id':
                el = self.driver.find_element_by_id(selector_value)
            elif selector_by == "n" or selector_by == 'name':
                el = self.driver.find_element_by_name(selector_value)
            elif selector_by == 'cs' or selector_by == 'css_selector':
                el = self.driver.find_element_by_css_selector(selector_value)
            elif selector_by == 'cn' or selector_by == 'classname':
                el = self.driver.find_element_by_class_name(selector_value)
            elif selector_by == "lt" or selector_by == 'link_text':
                el = self.driver.find_element_by_link_text(selector_value)
            elif selector_by == "plt" or selector_by == 'partial_link_text':
                el = self.driver.find_element_by_partial_link_text(selector_value)
            elif selector_by == "tn" or selector_by == 'tag_name':
                el = self.driver.find_element_by_tag_name(selector_value)
            elif selector_by == "x" or selector_by == 'xpath':
                el = self.driver.find_element_by_xpath(selector_value)
            elif selector_by == "ss" or selector_by == 'selector_selector':
                el = self.driver.find_element_by_css_selector(selector_value)
            else:
                raise NameError("Please enter a valid type of targeting elements.")
        except NoSuchElementException  :
            logger.error("{0}页面中未能找到{1}元素".format(self, selector_value))

        return el

    # 输入
    def input(self, selector, text):
        el = self.find_element(selector)
        try:
            el.clear()
            el.send_keys(text)
            logger.info("Had type \' %s \' in inputBox" % text)
        except NameError as e:
            logger.error("Failed to type in input box with %s" % e)

    # 点击
    def click(self, selector):
        el = self.find_element(selector)
        try:
            logger.info("The element \' %s \' was clicked." % el.text)
            el.click()
        except NameError as e:
            logger.error("Failed to click the element with %s" % e)

    @staticmethod
    def sleep(seconds):
        time.sleep(seconds)
        logger.info("Sleep for %d seconds" % seconds)

    def get_text(self,selector):
        el = self.find_element(selector)
        try:
            return el.text
        except NameError as e:
            logger.error("Failed to text the element with %s" % e)

    def switch_frame(self, selector):
        """
        多表单嵌套切换
        :param loc: 传元素的属性值
        :return: 定位到的元素
        """
        try:
            el = self.find_element(selector)
            return self.driver.switch_to_frame(el)
        except NoSuchElementException as e:
            logger.error("查找iframe异常-> {0}".format(e))

    def switch_windows(self, selector):
        """
        多窗口切换
        :param loc:
        :return:
        """
        try:
            el = self.find_element(selector)
            return self.driver.switch_to_window(el)
        except NoSuchElementException as e:
            logger.error("查找窗口句柄handle异常-> {0}".format(e))

    def switch_alert(self):
        """
        警告框处理
        :return:
        """
        try:
            return self.driver.switch_to_alert()
        except NoSuchElementException as e:
            logger.error("查找alert弹出框异常-> {0}".format(e))

LoginPage.py —— CNDS登录页面

from  pageObject.basePage import *
from selenium import webdriver
from common.readFile import ReadFile
from config import setting

login_el = ReadFile().readYaml(setting.TEST_Element_YAML + '/' + 'login.yaml')
data = ReadFile().readYaml(setting.TEST_DATA_YAML + '/' + 'login_data.yaml')

class CndsPage(BasePage):
    '''登录页面'''

    url = '/login'

    # 定位器,通过元素属性定位元素对象
    #选择账号密码登录
    chanlelogin_loc = login_el['testcase'][0]
    # 账号输入框
    username_loc = login_el['testcase'][1]
    # 密码输入框
    pwd_loc = login_el['testcase'][2]
    # 单击登录
    login_accout_loc = login_el['testcase'][3]

    def accout_login(self,accout,passwd):
        self.open_url(self.url)
        self.click(self.chanlelogin_loc)
        self.input(self.username_loc,accout)
        self.input(self.pwd_loc,passwd)
        self.click(self.login_accout_loc)

    # 定位器,通过元素属性定位检查项元素对象
    user_login_success_loc = login_el['check'][0]
    accout_id_loc = login_el['check'][1]
    accout_pawd_error_loc = login_el['check'][2]

    # 账号或密码错误提示
    def accout_passwd_error(self):
        return self.get_text(self.accout_pawd_error_loc)

    # 登录成功,跳转到个人资料页,获取用户名
    def get_account(self):
        self.click(self.user_login_success_loc)
        time.sleep(2)

    def user_login_success(self):
        return self.find_element(self.accout_id_loc).text

组织测试用例

  • 用户名密码正确点击登录
  • 用户名正确,密码错误点击登录
import unittest
from common import function,myUnit,readFile
from pageObject.loginPage import CndsPage
from time import sleep
from common.logger import Logger
from config import setting
import ddt

log = Logger()

testData= readFile.ReadFile().readYaml(setting.TEST_DATA_YAML + '/' + 'login_data.yaml')

@ddt.ddt
class LoginTest(myUnit.StartEnd):
    # @unittest.skip('skip this case')
    """CNDS登录测试"""
    def user_login_verify(self,account,passwd):
        """
        用户登录
        :param :account 账号
        :param passwd: 密码
        :return:
        """
        CndsPage(self.driver).accout_login(account,passwd)

    @ddt.data(*testData)
    def test_login_normal(self,datayaml):
        log.info("test_login1_normal is start run...")
        self.user_login_verify(datayaml['data']['accout'],datayaml['data']['passwd'])
        sleep(3)
        #断言与截屏
        po = CndsPage(self.driver)
        if datayaml['screenshot'] == 'login_success':
            po.get_account()
            function.inser_img(self.driver)
            self.assertEqual(po.user_login_success(), datayaml['check'][0], "登录成功,返回实际结果是->: {0}".format(po.user_login_success()))
        else:
            function.inser_img(self.driver)
            self.assertEqual(po.accout_passwd_error(), datayaml['check'][0],"登录失败,返回实际结果是->: {0}".format(po.accout_passwd_error()))
        print("test_login1_normal is test end!")

执行测试用例

import unittest
from  common.function import latest_report
from  common.sendMail import *
from config import setting
from thridLib.HTMLTestRunner import HTMLTestRunner
import time
import os,sys

sys.path.append(os.path.dirname(os.path.dirname(os.path.dirname(__file__))))
report_dir = setting.TEST_REPORT + '/report/'

def add_case(test_path=setting.TEST_DIR):
    discover = unittest.defaultTestLoader.discover(test_path, pattern="test*.py")
    return discover

def run_case(all_case,result_path=report_dir):
    print("start run testcase...")
    now = time.strftime("%Y-%m-%d %H_%M_%S")
    report_name = result_path + '/' + now + 'result.html'
    print("start write report...")

    #HTMLTestRunner测试报告
    with open(report_name, 'wb') as f:
        runner = HTMLTestRunner(stream=f, title='测试报告', description='用例执行情况')  # 定义测试报告
        runner.run(all_case)  # 执行测试用例
    f.close()

    print("find latest report...")
    # 查找最新的测试报告
    report = latest_report(result_path)
    # 邮件发送报告
    print("send email report...")
    send_mail(report)
    print("test end!")

if __name__ == '__main__':
    cases = add_case()
    run_case(cases)

测试报告

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Selenium Web自动化测试框架实践 的相关文章

  • 【测试开发】关于性能测试的各种指标

    关于性能测试的各种指标 本指标适用于使用性能测试进行性能测试项目技术质量评价依据 规范技术测试结果评价 统一性能测试技术测试质量度量 应用系统技术质量度量指标范围广泛 本文难以涵盖全部 预期读者为测试管理人员 测试实施人员 技术支持人员 项
  • Python自动化测试框架:Pytest和Unittest的区别

    pytest和unittest是Python中常用的两种测试框架 它们都可以用来编写和执行测试用例 但两者在很多方面都有所不同 本文将从不同的角度来论述这些区别 以帮助大家更好地理解pytest和unittest 1 原理 pytest是基
  • 使用miniserve快速搭建文件服务

    当我们想自己搭建一个 HTTP 文件服务向其他人分享文件 或者往其他设备上传输文件时 又不想花费时间去研究 Nginx IIS FTP 这些东西 我们可以通过 miniserve 一键生成简约 美观的文件服务器 访问 miniserve 客
  • python使用ctypes调用dll

    因为 ctypes 是内置模块 可以直接使用 from ctypes import 加载dll程序 from ctypes import dll CDLL test sdk dll 调用dll方法 直接调用 from ctypes impo
  • 微CLI工具箱-WeToolkit

    当需要将一个Python脚本快速提供给用户使用时 直接提供纯命令行指令给用户 不友好 如果开发可视化的GUI界面 又太废时间 而且无法在Linux服务器上使用 于是就整了这个微CLI工具箱 WeToolkit 解决这个问题 微CLI工具箱
  • 对个人博客系统进行web自动化测试(包含测试代码和测试的详细过程)

    目录 一 总述 二 登录页面测试 一些准备工作 验证页面显示是否正确 验证正常登录的情况 该过程中出现的问题 验证登录失败的情况 关于登录界面的总代码 测试视频 三 注册界面的自动化测试 测试代码 过程中出现的bug 测试视频 四 博客列表
  • 字节原来这么容易进,是面试官放水,还是公司实在是太缺人?

    本人211非科班 之前在字节和腾讯实习过 这次其实没抱着什么特别大的希望投递 没想到字节可以再给我一次机会 还是挺开心的 本来以为有个机会就不错啦 没想到能成功上岸 在这里要特别感谢帮我内推的同学 中间投递比较曲折 是他帮了我很多 非常负责
  • 性能自动化+locust

    性能自动化 locust 仅作为个人笔记 如有雷同 请联系删除 性能测试基础 1 性能测试相关概念 性能测试 测试软件的性能表现 考量软件运行的如何 一般关注时间 效率 资源占用等情况 响应时间 应用系统从用户发出请求开始 到客户端接收到所
  • 用户端APP自动化测试_L2

    目录 appium server 环境安装 capability 进阶用法 元素定位工具 高级定位技巧 xpath 定位 高级定位技巧 css 定位与原生定位 特殊控件 toast 识别 显式等待高级使用 高级控件交互方法 设备交互api
  • 测试开发——selenium1

    selenium1 1 什么是自动化测试 1 1 单元测试 1 2 接口测试 自动化的价值 脚本的复用率 复用率越高 价值越大 1 3 UI自动化 2 UI自动化的好处 3 自动化框架 4 webdriver的原理 5 selenium I
  • fiddler抓取,Android真机测试

    1 配置Fiddler抓取并解密HTTPS包 Fiddler默认是不抓取HTTPS包的 需要进行相应的配置 打开Fiddler 选择 Tools gt Fiddler Options 2 在弹出的对话框中选择 HTTPS 选项卡 3 勾选
  • 【测试开发】阿里十年总结之软件测试的价值

    阿里十年总结之软件测试的价值 1 前言 2 质量是什么 2 1 质量是一种奢侈品 2 2 质量是产品的特性 2 3 质量的重要性取决于业务 3 测试能给业务带来什么 3 1 为什么需要测试 3 2 从质量保障到研发效能 4 测试团队如何去突
  • 软件测试第一次做项目之银行项目【操作细节总结】

    在我们的日常在金融或银行软件测试工作中都有哪些内容需要测试 在这些测试的内容中如何去更好的掌握测试技能保证测试质量 一起来学习探讨交流 下面为银行测试点的概括 根据上图 我们可以从以下几个方面重点关注 1 管理端的测试主要是在管理后端对用户
  • 阿里4年测试经验分享 —— 测试外包干了3年后,我废了...

    去年国庆 我分享了一次一位阿里朋友的技术生涯 大家反响爆蓬 感觉十分有意思 今天我来分享一下我另一位朋友的真实经历 是不是很想听 没错 我这位朋友是曾经外包公司的测试开发 而且一干就是三年 三年后 他说他废了 虽说废的不是很彻底 但这三年他
  • 处理Selenium3+python3定位鼠标悬停才显示的元素

    这篇文章主要介绍了Selenium3 python3 如何定位鼠标悬停才显示的元素 文中通过简单代码给大家介绍的非常详细 需要的朋友可以参考下 先给大家介绍下Selenium3 python3 如何定位鼠标悬停才显示的元素 定位鼠标悬停才显
  • 测试用例设计方法之等效类,边界值

    概念 等价类划分是一种黑盒测试方法 把无限的测试变成有限的测试 把所有可能的输入数据 即程序的输入域划分成若干等价类 然后从每一个等价类中选取少数具有代表性的数据作为测试用例 依据需求将输入 特殊情况下会考虑输出 划分为若干个等价类 从等价
  • 测试——自动化测试(Selenium工具)

    目录 一 自动化测试的概念以及分类 二 Selenium web自动化测试工具 1 自动化测试的一些前置工作 2 第一个自动化实例 3 总结 编辑 三 Selenium常用方法 定位元素的方法 元素的操作 等待 强制等待 待补充 隐式等待
  • 公司新招了个字节拿36K的人,让我见识到了什么才是测试扛把子......

    5年测试 应该是能达到资深测试的水准 即不仅能熟练地开发业务 而且还能熟悉项目开发 测试 调试和发布的流程 而且还应该能全面掌握数据库等方面的技能 如果技能再高些的话 甚至熟悉分布式组件等高级技能 或者说 做个项目小组长 管个3 4号人 应
  • 测试开发学习路线

    测试开发学习路线 HI 大家好 我是Lee 通过某些圈子了解大家对于测试开发这个岗位了解的很模糊 对于技术栈不知道应该学习什么 接下来就通过各方面来说一下测试开发具体是做什么以及需要掌握哪些技术 1 了解测试开发 什么是测试开发 大家应该都
  • APK 逆向工程 - 解析 apk 基本信息和方法调用图

    导读 在 Android 开发中 我们很少使用 Android 逆向去分析 apk 文件的 但是作为一个测试人员 我们要对这个 apk 文件进行一系列的分析 审核 测试 这篇文章讲解如何解析一个 apk 文件 主要从下面几方面介绍 解析前准

随机推荐

  • unity按钮实现人物变大效果

    unity按钮实现人物变大效果 游戏里面模型变大效果的实现 如下动态图所示 点我下载 https download csdn net download weixin 43474701 71975042
  • java 通过pdf模板,生成PDF,并下载到本地

    注意 本例子是从向模板定义的变量赋值 而不是从无到有的来生成pdf 直接就能用 maven依赖
  • 精通MySQL之架构篇

    今天给大家分享的是大数据开发基础部分MySQL的第一篇 老刘讲点和别人不一样的内容 众多伙伴都知道MySQL的基础知识以及使用 但是对里面的原理知道的不多 咱们学知识只看表面绝对是不行的 所以老刘争取把MySQL的架构知识给大家讲明白 My
  • Shell编程之echo命令

    Shell 的 echo 指令与 PHP 的 echo 指令类似 都是用于字符串的输出 命令格式 echo string 您可以使用echo实现更复杂的输出格式控制 1 显示普通字符串 echo It is a test 这里的双引号完全可
  • Vue3 (computed函数,watch函数,watchEffect函数)

    1 computed函数 与vue2中computed配置功能一致 变化 需要引入 组合式的API
  • 树莓派第一讲:入门那些事(系统烧录、外设连接)

    目录 基本了解 系统烧录 连接外设 基本了解 树莓派4B是一款单板计算机 采用ARM架构处理器 配备4GB内存 Gigabit以太网口 多个USB接口 HDMI输出接口等 它具备1 5Ghz运行的64位四核处理器 最高支持以60fps速度刷
  • 因果推断 - 基础知识

    目录 因果关系之梯 因果图的路径结构 阻断 d 分离 混杂 结构因果模型 SCM 版权 转载前请联系作者获得授权 声明 部分内容出自因果关系之梯 已获得原作者授权 参考书籍 The Book of Why Judea Pearl 因果关系之
  • 什么是回调函数Callback----自己的一点理解

    何为回调函数 若把函数的指针作为函数参数传递给一个函数 当这个指着被用来调用它所指向的函数时 我们将该指针所指向的函数称为回调函数 回调函数与普通函数最大区别在于函数的调用 对普通函数而言 函数实现者可以直接拿来用 可以直接将它放在main
  • 金山逍遥网 sersync 服务器实时镜像同步方案

    金山逍遥网 sersync 服务器实时镜像同步方案 1 sersync rsync原理 2 inotify和sersync同步的区别 3 配置sersync rsync实现实时同步 2台centos7 4 一台装sersync一台装rsyn
  • 『网络安全』蜜罐到蜜网入门指南(三)蜜罐内部组成分析

    原创不易 点个赞呗 如果喜欢 关注 收藏不迷路 前言 大家好 网络安全 蜜罐到蜜网入门指南 进入第三篇 通过前面的内容 我们知道了什么是蜜罐以及蜜罐的作用和分类等 点击下方链接 可快速查看 相关文章 网络安全 蜜罐到蜜网入门指南 一 蜜罐初
  • php执行命令的函数和方法

    PHP提供4个专门的执行外部命令的函数 exec system passthru shell exec 1 exec 原型 string exec string command array output int return var 说明
  • Win10+Ubuntu双系统 使用EasyUEFI修复Ubuntu引导启动项

    某同事安装了Win10 Ubuntu双系统 有一天电脑突然坏了开不了机 把硬盘拆下放到别的机器上 发现是直接进入Win10系统 而不是grub选择界面 进F12也找不到ubuntu的启动项 最开始我先使用 Win10 Ubuntu双系统修复
  • 在项目中添加天气预报功能

    查看当地的天气情况 调用七日的天气预报情况 天气预报 注册账号获取appid和APPSecret使用 https www tianqiapi com api 图标可以直接在网站上下载
  • CoreDNS 惊现诡异 bug,导致服务大面积中断

    Sealos 公众号已接入了 GPT 4 完全免费 欢迎前来调戏 原文链接 https juejin cn post 7277471908417110053 我是 LEE 老李 一个在 IT 行业摸爬滚打 17 年的技术老兵 事件背景 某天
  • Flutter开发(十二)—— 页面跳转与返回

    示例代码 以下代码展示页面跳转与返回 抛开所有复杂因素 只展示最简单的跳转 第一个页面 点击按钮时onPressed 进行相应 通过 Navigator push 和 MaterialPageRoute 进行页面跳转功能实现 第二个页面 点
  • python中百分数如何表达_Python转换百分数表示法

    YAML中任何以百分号结尾的数字序列都将 通常作为字符串标量加载 因为 不会 标量匹配任何其他模式 尤其是不匹配整数的模式 或浮动 当然 您可以递归地遍历数据结构 从YAML和patch加载 但是如果在 数据结构 用于构造特定对象 递归到这
  • passwd: Authentication token manipulation error----linux

    author skatetime 2009 04 11 更改centos4 7 linux的root密码 报 passwd Authentication token manipulation error 如下所示 root ticket A
  • react移动端适配

    一 自定义方法配置 1 使用JavaScript动态设置根元素的字体大小 为了实现响应式的自适应效果 可以结合JavaScript根据屏幕大小动态设置根元素的字体大小 可以使用window innerWidth获取窗口的宽度 然后根据需要的
  • Q_PROPERTY

    一 定义 Qt提供了一个成熟的属性系统 Q PROPERTY是一个宏 用来在类中声明一个属性 由于该特性是Qt所特有的 需要moc进行编译 故必须继承QObject 查看Qt助手 我们可以看到如下定义 看不懂 其实 这是一个正则表达式 我们
  • Selenium Web自动化测试框架实践

    功能实现 自动运行用例 自动生成测试报告 自动断言与截图 自动将最新测试报告发送到指定邮箱 自动生成测试报告 数据 页面元素 测试用例分离 执行日志 分布式执行 配置化文件 元素 数据 实践功能 https passport csdn ne