用户端Web自动化测试_L3

目录:

  1. 浏览器复用
  2. Cookie 复用
  3. pageobject设计模式
  4. 异常自动截图
  5. 测试用例流程设计
  6. 电子商务产品实战

1.浏览器复用

复用浏览器简介

 

为什么要学习复用浏览器?

  • 自动化测试过程中,存在人为介入场景
  • 提高调试UI自动化测试脚本效率
     

复用已有浏览器-配置步骤

  1. 需要退出当前所有的谷歌浏览器(特别注意)

  2. 输入启动命令,通过命令启动谷歌浏览器

    1. 找到 chrome 的启动路径
    2. 配置环境变量
  3. 验证是否启动成功

  • windows:chrome –remote-debugging-port=9222
  • mac:Google Chrome –remote-debugging-port=9222

 

 

 

 代码示例:

from selenium import webdriver
from selenium.webdriver.chrome.options import Options
from selenium.webdriver.common.by import By

option = Options()

option.debugger_address = 'localhost:9222'

driver = webdriver.Chrome(options=option)

driver.get("https://work.weixin.qq.com/wework_admin/frame")

driver.find_element(By.CSS_SELECTOR,'.ww_indexImg_AddMember').click()

 2.Cookie 复用

cookie 是什么?

  • Cookie 是一些认证数据信息,存储在电脑的浏览器上
  • 当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息

 为什么要使用Cookie自动化登录?

  • 复用浏览器仍然在每次用例开始都需要人为介入
  • 若用例需要经常执行,复用浏览器则不是一个好的选择
  • 大部分cookie的时效性都很长,扫一次可以使用多次

  

 常见问题

  1. 企业微信cookie有互踢机制。在获取cookie成功之后。不要再进行扫码操作!!!!
  2. 获取cookie的时候,即执行代码获取cookie时,一定要确保已经登录
  3. 植入cookie之后需要进入登录页面,刷新验证是否自动登录成功。

 代码示例:

import time

import yaml
from selenium import webdriver


class TestCookieLogin:
    def setup_class(self):
        self.drvier = webdriver.Chrome()
        self.drvier.implicitly_wait(3)

    def teardown_class(self):
        self.drvier.quit()

    def test_get_cookies(self):
        # 1. 访问企业微信主页/登录页面
        self.drvier.get("https://work.weixin.qq.com/wework_admin/frame#contacts")
        # 2. 等待20s,人工扫码操作
        time.sleep(15)
        # 3. 等成功登陆之后,再去获取cookie信息
        cookie = self.drvier.get_cookies()
        print(cookie)
        # 4. 将cookie存入一个可持久存储的地方,文件
        # 打开文件的时候添加写入权限
        with open("./datas/doc/cookie.yaml", "w") as f:
            # 第一个参数是要写入的数据
            yaml.safe_dump(cookie, f)

    def test_add_cookie(self):
        # 1. 访问企业微信主页面
        self.drvier.get("https://work.weixin.qq.com/wework_admin/frame#contacts")
        # 2. 定义cookie,cookie信息从已经写入的cookie文件中获取
        cookie = yaml.safe_load(open("./datas/doc/cookie.yaml"))
        # 3. 植入cookie
        for c in cookie:
            self.drvier.add_cookie(c)
        time.sleep(3)
        # 4.再次访问企业微信页面,发现无需扫码自动登录,而且可以多次使用
        self.drvier.get("https://work.weixin.qq.com/wework_admin/frame#contacts")

代码结构:

  

3.pageobject设计模式

传统 UI 自动化的问题

  • 无法适应 UI 频繁变化
  • 无法清晰表达业务用例场景
  • 大量的样板代码 driver/find/click

POM 模式的优势

  • 降低 UI 变化导致的测试用例脆弱性问题
  • 让用例清晰明朗,与具体实现无关

 POM 建模原则

  • 字段意义
    • 不要暴露页面内部的元素给外部
    • 不需要建模 UI 内的所有元素
  • 方法意义
    • 用公共方法代表 UI 所提供的功能
    • 方法应该返回其他的 PageObject 或者返回用于断言的数据
    • 同样的行为不同的结果可以建模为不同的方法
    • 不要在方法内加断言

POM 使用方法

  • 把元素信息和操作细节封装到 PageObject 类中
  • 根据业务逻辑,在测试用例中链式调用

PO简介:

Page Object(简称PO)模式,是Selenium实战中最为流行,并且是自动化测试中最为熟悉和推崇的一种设计模式。在设计自动化测试时,把页面元素和元素的操作方法按照页面抽象出来,分离成一定的对象,然后再进行组织。做web自动化最头疼的一个问题,莫过于页面变化了,如果没有使用PO设计模式,页面一变化就意味着之前的元素定位甚至元素的操作方法不能用了,需要重新修改。你需要一个一个从测试脚本中把需要修改的元素定位方式、元素的操作方法找出来,然后一一地修改。这样的自动化脚本不但繁琐,维护成本也极高。

而page object模式就可以很好地解决这个问题,优点:

  1. 减少代码冗余。
  2. 业务和实现分离。
  3. 降低维护成本。

那到底什么是Page Object模式,见名知意,就是页面对象,在实际自动化测试中,一般对脚本分为三层:

  1. 对象层: 用于存放页面元素定位(object_layer)
  2. 逻辑层: 用于存放一些封装好的功能用例模块(logical_layer)
  3. 业务层: 用于存放我们真正的测试用例的操作部分(business_layer)

除了以上三层,还有一个基础层(base_layer),基础层主要是针对selenium的一些常用方法,根据实际业务需要进行二次封装,如点击、输入等操作加入一些等待、日志输入、截图等操作,方便以后查看脚本的运行情况及问题排查。

代码示例:(传统的测试方法)

test_tradition_search.py

from selenium import webdriver
from selenium.webdriver.common.by import By


class TestSearch:

    def setup_class(self):
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitly_wait(3)

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

    def test_search(self):
        self.driver.get("https://xueqiu.com/")
        # 输入搜索关键词
        self.driver.find_element(By.NAME, "q").send_keys("阿里巴巴-SW")
        # 点击搜索按钮
        self.driver.find_element(By.CSS_SELECTOR, "i.search").click()
        # 获取搜索结果
        name = self.driver.find_element(By.XPATH, "//table//strong").text
        # 断言
        assert name == "阿里巴巴-SW"

代码示例:(po模式) 

template: 用来存放开发模版 - Gitee.com

项目结构:

  

4.异常自动截图

实现原理

  • 装饰器
  • 自动化关键数据记录
    • 截图
    • 日志
    • page_source

代码示例:

 test_record_exception_zhuangshiqi.py

import time

import allure
from selenium import webdriver
from selenium.webdriver.common.by import By

from web_automation_testing.first_web_automation_testing.utils.log_util import logger


def ui_exception_record(func):
    def inner(*args, **kwargs):

        try:
            return func(*args, **kwargs)
        except Exception:
            logger.warning('执行过程发生异常!')
            driver = args[0].driver

            timestamp = int(time.time())

            img_path = f"./datas/screenshot/image_{timestamp}.png"
            driver.save_screenshot(img_path)

            page_source_path = f"./datas/pagesource/page_source_{timestamp}.html"
            with open(page_source_path, 'w', encoding='utf8') as f:
                f.write(driver.page_source)

            allure.attach.file(img_path, name="picture", attachment_type=allure.attachment_type.PNG)
            allure.attach.file(page_source_path, name="pagesource", attachment_type=allure.attachment_type.TEXT)
            # allure.attach.file(page_source_path,name="pagesource",attachment_type=allure.attachment_type.HTML)
            raise Exception

    return inner


class TestRecord:
    def setup_class(self):
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitly_wait(5)

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

    @ui_exception_record
    def test_baidu(self):
        self.driver.get("https://www.baidu.com/")
        self.driver.find_element(By.ID, 'su1')

项目结构:

运行结果:

  

5.测试用例流程设计

现有测试用例的问题

  • 可维护性不高
  • 可读性较差
  • 稳定性较差

用例结构设计

  • 测试用例的编排
  • 测试用例的项目结构

web自动化测试-用例设计

类型框架对应作用
前置setup_class/BeforeAll准备测试数据
实例的初始化
setup/BeforeEach恢复用例初始状态
数据清理(也可以在用例级别完成)
后置teardown_class/AfterAlldriver进程退出
teardown/AfterEach恢复用例初始状态
数据清理(也可以在用例级别完成)

恢复用例初始状态

  1. 用例1 执行过程经过A->B->C 三个页面
  2. 用例2 执行过程经过A->B->C 三个页面
  3. 用例1 执行完成之后执行用例2

PlantUML diagram

PlantUML diagram

问题:单条用例执行完成之后如果不恢复下一条用例的开始状态(回复用例初始页面),则会影响下一条用例的执行。

  • 解决方案:
    • 每条用例执行完成都quit()(影响执行效率)
    • 封装一个方法,用例执行完成之后回到首页

数据清理

  • 清理策略
    • 在前置处理中执行
    • 在后置处理中执行
  • 清理方式
    • 调用业务接口
    • 通过UI自动化方式操作
    • 连接数据库执行SQL(不推荐)

6.电子商务产品实战

产品分析

  • 产品:Litemall商城系统
  • 功能:商品类目管理
  • litemall

测试用例-新增类目

  • 用户登录
  • 进入商品类目菜单
  • 点击添加
  • 创建商品类目
  • 获取操作结果
  • 断言测试结果

PlantUML diagram

测试用例-删除类目

  • 用户登录
  • 进入商品类目菜单
  • 点击添加
  • 创建商品类目
  • 点击删除
  • 获取操作结果
  • 断言测试结果

PlantUML diagram

代码示例:(传统示例)

test_tradition_litemall.py

import time
import allure
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.support.wait import WebDriverWait
from web_automation_testing.test_litemall_1.utils.log_util import logger


class TestLitemall:

    # 前置动作
    def setup_class(self):
        self.driver = webdriver.Chrome()
        self.driver.implicitly_wait(3)
        # 登录
        self.driver.get("http://litemall.hogwarts.ceshiren.com/")
        # 问题,输入框内有默认值,此时send——keys不回清空只会追加
        # 解决方案: 在输入信息之前,先对输入框完成清空
        # 输入用户名密码
        self.driver.find_element(By.NAME, "username").clear()
        self.driver.find_element(By.NAME, "username").send_keys("manage")
        self.driver.find_element(By.NAME, "password").clear()
        self.driver.find_element(By.NAME, "password").send_keys("manage123")
        # 点击登录按钮
        self.driver.find_element(By.CSS_SELECTOR,
                                 ".el-button--primary").click()
        # 窗口最大化
        self.driver.maximize_window()

    # 后置动作
    def teardown_class(self):
        self.driver.quit()

    def get_screen(self):
        timestamp = int(time.time())
        # 注意:!! 一定要提前创建好images 路径
        image_path = f"./datas/screenshot/image_{timestamp}.PNG"
        # 截图
        self.driver.save_screenshot(image_path)
        # 讲截图放到报告的数据中
        allure.attach.file(image_path, name="picture",
                           attachment_type=allure.attachment_type.PNG)

    # 新增功能
    def test_add_type(self):
        # 点击商场管理/商品类目,进入商品类目页面
        # 进入商品类目页面
        self.driver.find_element(By.XPATH, "//*[text()='商场管理']").click()
        self.driver.find_element(By.XPATH, "//*[text()='商品类目']").click()
        # 添加商品类目操作
        self.driver.find_element(By.XPATH, "//*[text()='添加']").click()
        self.driver.find_element(By.CSS_SELECTOR,
                                 ".el-input__inner").send_keys("新增商品测试")

        # ==============显示等待优化方案2: 自定义显式等待条件
        def click_exception(by, element, max_attempts=5):
            def _inner(driver):
                # 多次点击按钮
                actul_attempts = 0  # 实际点击次数
                while actul_attempts < max_attempts:
                    # 进行点击操作
                    actul_attempts += 1  # 每次循环,实际点击次数加1
                    try:
                        # 如果点击过程报错,则直接执行 except 逻辑,并切继续循环
                        # 没有报错,则直接return 循环结束
                        driver.find_element(by, element).click()
                        return True
                    except Exception:
                        logger.debug("点击的时候出现了一次异常")
                # 当实际点击次数大于最大点击次数时,结束循环并抛出异常
                raise Exception("超出了最大点击次数")

            # return _inner() 错误写法
            return _inner

        WebDriverWait(self.driver, 10).until(click_exception(By.CSS_SELECTOR,
                                                             ".dialog-footer .el-button--primary"))

        # ===========================使用显式等待优化
        # 如果没找到,程序也不应该报错
        res = self.driver.find_elements(By.XPATH,
                                        "//*[text()='新增商品测试']")
        self.get_screen()
        # 数据的清理一定到放在断言操作之后完成,要不然可能会影响断言结果
        self.driver.find_element(By.XPATH,
                                 "//*[text()='新增商品测试']/../..//*[text()='删除']").click()
        logger.info(f"断言获取到的实际结果为{res}")
        # 断言产品新增后是否成功找到
        assert res != []

    # 删除功能
    def test_delete_type(self):
        # ================ 造数据步骤
        # 点击商场管理/商品类目,进入商品类目页面
        # 进入商品类目页面
        self.driver.find_element(By.XPATH, "//*[text()='商场管理']").click()
        self.driver.find_element(By.XPATH, "//*[text()='商品类目']").click()
        # 添加商品类目操作
        self.driver.find_element(By.XPATH, "//*[text()='添加']").click()
        self.driver.find_element(By.CSS_SELECTOR,
                                 ".el-input__inner").send_keys("删除商品测试")
        ele = WebDriverWait(self.driver, 10).until(
            expected_conditions.element_to_be_clickable(
                (By.CSS_SELECTOR, ".dialog-footer .el-button--primary")))
        ele.click()
        # ============完成删除步骤
        self.driver.find_element(By.XPATH,
                                 "//*[text()='删除商品测试']/../..//*[text()='删除']").click()
        # 断言
        WebDriverWait(self.driver, 10).until_not(
            expected_conditions.visibility_of_any_elements_located((By.XPATH,
                                                                    "//*[text()='删除商品测试']")))
        # 问题: 因为代码执行速度过快,元素还未消失就捕获了。
        # 解决: 确认该元素不存在后,再捕获
        res = self.driver.find_elements(By.XPATH,
                                        "//*[text()='删除商品测试']")
        logger.info(f"断言获取到的实际结果为{res}")
        assert res == []

PO模式设计原则

  • 不要暴露页面内部的元素给外部
  • 不需要建模 UI 内的所有元素
  • 要用公共方法代表 UI 所提供的功能
  • 同样的行为不同的结果可以建模为不同的方法
  • 方法应该返回其他的 PageObject ,或者返回用于断言的数据
  • 不要在方法内加断言

PO模式改造

PlantUML diagram

 梳理业务操作流程

PlantUML diagram

 梳理前置和后置

代码示例:

template: 用来存放开发模版

项目结构:

  

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

测试框架pytest教程(3)夹具-@pytest.fixture

内置fixture Fixture使用pytest.fixture装饰&#xff0c;pytest有一些内置的fixture 命令可以查看内置fixture pytest --fixtures fixture范围 在pytest中&#xff0c;夹具&#xff08;fixtures&#xff09;具有不同的作用范围&#xff08;scope&#xff09;&#xff0c;用于…

JAVA毕业设计095—基于Java+Springboot+Vue的酒店管理系统(源码+数据库)

基于JavaSpringbootVue的酒店管理系统(源码数据库)095 一、系统介绍 本系统前后端分离(网页端和app端都有) 本系统分为管理员、酒店管理员、酒店员工、用户四种角色(角色菜单可自行分配) 用户功能&#xff1a; 注册、登录、酒店搜索、酒店列表、酒店预订、我的收藏、我的订…

ACM模式(基础输入输出)

import java.lang.*; import java.util.*; public class Main{public static void main(String[] args){Scanner in new Scanner(System.in);while(in.hasNextInt()){//下一行是否有数据int ain.nextInt();int bin.nextInt();System.out.println(ab);}} }Java方法间的调用 http…

上海交大ACM班总教头团队重磅新作,带你动手学机器学习(文末赠书4本)

目录 0 写在前面1 什么是机器学习&#xff1f;2 ACM 班总教头&#xff1a;俞勇3 动手学习机器学习赠书活动 0 写在前面 机器学习强基计划聚焦深度和广度&#xff0c;加深对机器学习模型的理解与应用。“深”在详细推导算法模型背后的数学原理&#xff1b;“广”在分析多个机器…

git merge规则

参考文档&#xff1a;https://juejin.cn/post/7129333439299321887 丹尼尔&#xff1a;Hi&#xff0c;蛋兄&#xff0c;周杰伦都出新专辑了&#xff0c;你咋还不更新啊&#xff0c;真的打算半年一更啊&#xff1f; 蛋先生&#xff1a;好像确实是这样&#xff0c;要不&#xff0…

微信小程序的springboot实现 个人行程日程安排系统

本站后台采用Java的springboot框架进行后台管理开发&#xff0c;可以在浏览器上登录进行后台数据方面的管理&#xff0c;MySQL作为本地数据库&#xff0c;微信小程序用到了微信开发者工具&#xff0c;充分保证系统的稳定性。系统具有界面清晰、操作简单&#xff0c;功能齐全的特…

我是大运火炬手丨民营企业家极米钟波:大运精神激励企业不断创新、追求极致

7月26日&#xff0c;成都第31届世界大学生夏季运动会火炬传递成都站第五传递日活动&#xff0c;在成都3所高校以及东安湖体育公园继续进行。极米科技股份有限公司&#xff08;以下简称“极米科技”&#xff09;董事长钟波是第92棒火炬手。 火炬手钟波 大学求学在成都&#xff…

《知识图谱与大模型融合实践研究报告》发布,创邻科技参编

近期&#xff0c;第三届知识图谱产业发展论坛暨知识图谱与大模型融合研讨会在北京召开。会上&#xff0c;《知识图谱与大模型融合实践研究报告》正式发布&#xff01; 该白皮书是由中国电子技术标准化研究院依托知识图谱产业推进方阵、全国信标委人工智能分委会知识图谱工作组…

TCP可靠性机制

确认号/序列号/ACK TCP帮助确保数据的准确传递。为了做到这一点&#xff0c;其使用了一些特殊的标记和信息&#xff0c;其中包括序号、确认号和ACK字段。 其中&#xff0c;它将每个字节的数据都进行了编号. 即为序列号. 序列号&#xff1a;就像给书中的每一页都编了号码一样&a…

Redis三种持久化方式详解

一、Redis持久性 Redis如何将数据写入磁盘 持久性是指将数据写入持久存储&#xff0c;如固态磁盘&#xff08;SSD&#xff09;。Redis提供了一系列持久性选项。其中包括&#xff1a; RDB&#xff08;快照&#xff09;&#xff1a;RDB持久性以指定的时间间隔执行数据集的时间点…

vue 简单实验 v-if 条件判定

1.代码 <script src"https://unpkg.com/vuenext" rel"external nofollow" ></script> <div id"conditional-rendering"><span v-if"seen">现在你看到我了</span> </div> <script> const C…

语法篇--XML数据传输格式

一、XML概述 1.1简介 XML&#xff0c;全称为Extensible Markup Language&#xff0c;即可扩展标记语言&#xff0c;是一种用于存储和传输数据的文本格式。它是由W3C&#xff08;万维网联盟&#xff09;推荐的标准&#xff0c;广泛应用于各种系统中&#xff0c;如Web服务、数据…

回归预测 | MATLAB实现SA-ELM模拟退火算法优化极限学习机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现SA-ELM模拟退火算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现SA-ELM模拟退火算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本…

Java“牵手”虾皮商品详情数据,根据商品ID获取虾皮(Shopee商品详情数据接口,虾皮API接口申请指南

虾皮&#xff08;shopee&#xff09;商城是一个跨境网上批发购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取虾皮商品详情数据&#xff0c;您可以通过开放平台的接口或者直接访问虾皮商城的网页来获取商品详情信息。以下…

vim 配置环境变量与 JDK 编译器异常

vim 配置环境变量 使用 vim 打开系统中的配置信息&#xff08;不存在将会创建&#xff09;&#xff1a; vim ~/.bash_profile 以配置两个版本 JDK 为例&#xff08;前提是已安装 JDK&#xff09;,使用上述命令打开配置信息&#xff1a; 输入法调成英文&#xff0c;输入 i&…

低压风机单片机方案

低压风机通常由电机、转子、机壳、进气管、出气管、齿轮和减速机等组成。电机带动转子旋转&#xff0c;旋转的转子带动齿轮和减速机转动&#xff0c;进而形成空气被吸入转子内部&#xff0c;通过旋转而产生的离心力把气体压缩&#xff0c;并将气体排出。 低压风机方案的主控型…

设置p标签中的内容不换行展示

设置p标签中的内容不换行展示 /*不换行*/white-space: nowrap;/*多余的部分以顶点点点的形式进行展示*/text-overflow: ellipsis;/*隐藏多余的部分*/overflow: hidden;效果图

微服务中间件--统一网关Gateway

统一网关Gateway 8.统一网关Gatewaya.搭建网关服务b.路由断言工厂c.路由过滤器GatewayFilterd.全局过滤器GlobalFiltere.过滤器的执行顺序f.网关的cors跨域配置 8.统一网关Gateway 网关功能&#xff1a; 身份认证和权限校验服务路由、负载均衡请求限流 网关的技术实现 在Spr…

Unity 之 Transform.Translate 实现局部坐标系中进行平移操作的方法

文章目录 Translate 默认使用局部坐标也可以转换成世界坐标 Translate 默认使用局部坐标 在Unity中&#xff0c;Transform.Translate是用于在游戏对象的局部坐标系中进行平移操作的方法。这意味着它将游戏对象沿着其自身的轴进行移动&#xff0c;而不是世界坐标轴。这在实现物…

docker 搭建 ElasticSearch

1、拉取镜像 docker pull elasticsearch:8.8.12、在机器本地新建文件夹并赋予权限 mkdir -p /home/elasticsearch/configmkdir -p /home/elasticsearch/datamkdir -p /home/elasticsearch/pluginschmod 777 /home/elasticsearch/configchmod 777 /home/elasticsearch/datachm…
最新文章