本文大纲截图:

1、PO模式基本介绍【文末免费分享自动化测试学习资源】

概念:PO是Page Object的缩写,PO模式是自动化测试项目开发实践的最佳设计模式之一。

作用:通过对界面元素的封装减少冗余代码,同时在后期维护中,若元素定位发生变化, 只需要调整页面元素封装的代码,提高测试用例的可维护性、可读性。

2、PO模式核心思想

PO模式核心思想:方法封装。

概念: 方法封装是将一些有共性的或多次被使用的代码提取到一个方法中,供其他地方调用

目的: 用最少的代码实现最多的功能

好处:

  • 避免代码冗余

  • 容易维护

  • 隐藏代码实现的细节

套路:

  • 1)确定方法的存放位置:找位置

  • 2)给方法起个合适名字:起名字

  • 3)放入要封装的代码内容:放代码

  • 4)确认是否需要参数和返回值:确必要

  • 5)调用封装好的方法使用:做调用

PO模式学习思路:

采用版本迭代的方式来学习,便于对不同版本的优缺点进行对比和理解。

案例: 对TPshop项目的登录模块进行自动化测试。登录模块包含了很多测试用例,如:账号不存在、密码错误、验证码错误、登录成功等,从中选取代表性的用例来演示。

选择的测试用例:

  • 账号不存在

    • 1)点击首页"登录"链接,进入登录页面

    • 2)输入一个不存在的用户名

    • 3)输入密码

    • 4)输入验证码

    • 5)点击登录按钮

    • 6)获取错误提示信息

  • 密码错误

    • 1)点击首页"登录"链接,进入登录页面

    • 2)输入用户名

    • 3)输入一个错误的密码

    • 4)输入验证码

    • 5)点击登录按钮

    • 6)获取错误提示信息

版本迭代:

  • V1:不使用任何设计模式和单元测试框架

  • V2:使用PyTest管理用例,并删除多余的注释掉的代码

    • 1)按模块新建测试类

    • 2)提取出setupteardown函数中的方法内容;如:setup:实例化浏览器对象driver,打开网页,最大化浏览器,设置隐式等待;teardown:暂停3秒、关闭/退出浏览器

    • 3)提取出setup_classteardown_class函数中的方法内容;将共同的步骤:打开首页、点击登录进入登录页面 提取到setup函数中;注释掉两个函数中的“ # 1、点击首页"登录"链接,进入登录页面”代码

  • V3:使用方法封装的思想,对代码进行优化。定义获取驱动对象的工具类,封装“获取弹出框的提示消息”。

  • V4:PO页面元素封装步骤

    • 1)对应页面创建页面 PO 代码文件,命名规则:页面功能_page.py,例如:login_page.py

    • 2)定义三个类:

    • 格式:对象层(XxxPage)、操作层(XxxHandle)、业务层(XxxTask)

    • 3)对象层:init 方法中获取浏览器对象;自定义方法:封装元素定位方法;封装元素定位方法需要添加返回值!

    • 4)操作层:init 方法获取对象层对象,根据类名写对应变量名;自定义方法:封装元素操作方法。

    • 5)业务层:init 方法获取操作层对象,根据类名写对应变量名;自定义方法:封装测试业务逻辑。

    • 6)在测试用例文件中,实例化业务层对象,调用测试业务方法,执行测试

  • V5:将元素的定位方法及特征值封装成属性,能够实现集中管理目标元素的定位方法及特征

    • 如:利用元素定位方法find_elementBy将page页面元素信息集中放在page的__init__文件中。

  • V6:PO模式深入封装,把共同操作提取封装到父类中,子类直接调用父类的方法

    • page页面的公共方法:初始化方法、查找元素方法、点击元素方法、输入方法、获取文本方法、截图方法 ......

    • 封装工具类:get_driverget_loggerread_txtread_json ......

3、PO模式设计说明

模式说明:

  • 说明:PO模式又可以叫POM,是 UI 自动化测试中一个非常流行的设计模式(代码套路)

  • 核心:将元素定位、操作、业务逻辑 拆分为三个层面(每个曾铭对应一个单独的类),然后通过调用完成最终的测试执行行为的过程。

  • 好处:就是有元素变化,只需要维护每一个Page就行了,测试步骤变化,只需要维护TestCase即可

设计步骤:

  • 1)首先抽象封装一个Base类,这个基类拥有一些指向Webdriver实例的属性,然后每一个Page继承基类Base,可以通过driver管理每一个Page中的元素,而且在Page中将这些操作封装为一个一个的方法。

  • 2)Page类封装页面元素对象,继承Base类,调用Base类中封装的操作元素的方法;并组合业务流程方法供TestCase类调用。

  • 3)TestCase继承unittest里面的TestCase类,并且依赖page类,进行组织测试步骤的工作。

4、PO模式三层结构

操作层(基类base):

  • 操作层:对元素操作方法封装

  • 命名举例:

    • 模块名:base.py

    • 函数名:class Base:

    • 方法名:def base_find():def base_click():

  • page页面一些公共的方法:

    • 初始化方法

    • 查找元素方法

    • 点击元素方法

    • 输入方法

    • 获取文本方法

    • 截图方法

    • ......

对象层(page):

  • 对象层:对元素定位方法封装

  • 命名规则:

    • 模块名:page+下划线+实际操作模块名称。

    • 函数名(类名):使用大驼峰讲模块名称抄进来,有下划线去掉下划线。继承Base类。

    • 方法名:根据业务需求每个操作步骤单独封装一个方法(涉及元素,将每个元素操作单独封装一个操作方法)。

  • 命名举例:

    • 模块名:page_login.py

    • 函数名(类名):class PageLogin(Base):

    • 方法名:def page_input_username(): 输入用户名

  • 注意:一个页面封装成一个对象,并继承 base

  • 组合业务方法(组装):根据需求组装以上操作步骤。如:page_login

业务层(scripts):

  • 业务层:测试业务逻辑封装,将一个或多个操作组合起来完成一个业务功能。

  • 命名规则:

    • 模块名:test+数字+下划线+实际操作模块名称;如果测试用例存在先后顺序,则可加上数字。

    • 测试业务名称:以大驼峰方法将模块名抄进来,有下划线去掉下划线。

    • 方法名:def test_login():

  • 命名举例:

    • 模块名:test01_login.py

    • 测试业务名:class TestLogin():

    • 方法名:def test_login():

  • 说明:业务层实际就是测试脚本,并且要导包调用page页面封装的方法

  • 如登录业务:需要输入账号、密码、点击登录三个操作

  • 方法:

    • 1)初始化方法 setup(),注:在unittest框架中不能使用 __init__初始化方法。如:实例化页面对象、前置操作(如:打开浏览器等)

    • 2)结束方法 teardown()。如:关闭驱动

    • 3)测试方法。如:根据要操作的业务来实现

  • 步骤:

  # 导包# 新建测试类# setup# teardown# 业务测试方法# 调用功能方法(如 登录方法)# 获取登录提示信息# 断言# try 捕获异常# 截图

5、PO模式下的项目结构

PO模式下的主要项目文件夹:basepagescripts(cases)runtoolsdataimagelogreport

base

  • base.py

import time
from time import sleep
from selenium.webdriver.support.wait import WebDriverWait
from day11_tpshop import page
from day11_tpshop.base.get_logger import GetLogger# 获取log日志器
log = GetLogger().get_logger()class Base:def __init__(self, driver):log.info("[base:]正在获取初始化driver对象:{}".format(driver))self.driver = driver# 查找元素方法 封装def base_find(self, loc, timeout=30, poll=0.5):log.info("[base]:正在定位:{}元素,默认定位超时时间为:{}".format(loc, timeout))# 使用显式等待 查找元素return WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll).until(lambda x: x.find_element(*loc))# 点击元素方法 封装def base_click(self, loc):log.info("[base]:正在对:{}元素执行点击事件".format(loc))self.base_find(loc).click()# 输入元素方法 封装def base_input(self, loc, value):log.info("[base]:正在获取:{}元素".format(loc))# 获取元素el = self.base_find(loc)log.info("[base]:正在对:{}元素执行清空操作".format(loc))# 输入前 清空el.clear()log.info("[base]:正在给{}元素输入内容:{}".format(loc, value))# 输入el.send_keys(value)# 获取文本信息方法 封装def base_get_text(self, loc):log.info("[base]:正在获取{}元素文本值".format(loc))return self.base_find(loc).text# 截图方法 封装def base_get_img(self):log.info("[base]:断言出错,调用截图")self.driver.get_screenshot_as_file("../image/{}.png".format(time.strftime("%Y_%m_%d %H_%M_%S")))# 判断元素是否存在方法 封装def base_elememt_is_exist(self, loc):try:self.base_find(loc, timeout=2)log.info("[base]:{}元素查找成功,存在页面".format(loc))return True  # 代表元素存在except:log.info("[base]:{}元素查找失败,不存在当前页面".format(loc))return False  # 代表元素不存在# 回到首页(购物车、下订单、支付)都需要用到此方法def base_index(self):# 暂停2秒sleep(2)log.info("[base]:正在打开首页")self.driver.get(page.URL)# 切到frame表单方法 以元素属性切换def base_switch_frame(self, element):log.info("[base]:正在切换到frame表单")self.driver.switch_to.frame(element)# 回到默认目录方法def base_default_content(self):log.info("[base]:正在返回默认目录")self.driver.switch_to.default_content()# 切换窗口方法def base_switch_to_window(self, title):log.info("正在执行切换title值为:{}窗口".format(title))self.base_get_title_handle(title)# self.driver.switch_to.window(self.base_get_title_handle(title))# 获取指定title页面的handle方法def base_get_title_handle(self, title):# 获取当前页面所有的handleshandles = self.driver.window_handles# 遍历handlefor handle in handles:log.info("正在遍历handles:{}-->{}".format(handle, handles))# 切换 handleself.driver.switch_to.window(handle)log.info("切换:{}窗口".format(handle))# 获取当前页面title 并判断 是否等于 指定参数titlelog.info("条件成立!返回当前handle{}".format(handle))if self.driver.title == title:# 返回 handlereturn handle
  • get_driver.py

from selenium import webdriver
from day11_tpshop import pageclass GetDriver:driver = None# 获取 driver@classmethoddef get_driver(cls):if cls.driver is None:cls.driver = webdriver.Chrome()# 最大化浏览器cls.driver.maximize_window()# 打开 urlcls.driver.get(page.URL)# 返回 driverreturn cls.driver# 关闭 driver@classmethoddef quit_driver(cls):if cls.driver:cls.driver.quit()# 必须置空操作cls.driver = Noneif __name__ == '__main__':GetDriver().quit_driver()
  • get_logger.py

import logging.handlers
import timeclass GetLogger:logger = None# 获取logger@classmethoddef get_logger(cls):if cls.logger is None:# 获取 logger 日志器 并设置名称为“admin”cls.logger = logging.getLogger("admin")# 设置日志级别cls.logger.setLevel(logging.INFO)# 获取 控制台处理器sh = logging.StreamHandler()# 获取 文件处理器 根据时间分割th = logging.handlers.TimedRotatingFileHandler("../log/{}.log".format(time.strftime("%Y_%m_%d %H_%M_%S")),when="S",interval=1,backupCount=3,encoding="utf-8")# 设置 文件处理器 日志级别th.setLevel(logging.ERROR)# 获取 格式器fmt = "%(asctime)s %(levelname)s [%(name)s] [%(filename)s %(funcName)s %(lineno)d] - %(message)s"fm = logging.Formatter(fmt)# 将 格式器 添加到 处理器sh.setFormatter(fm)th.setFormatter(fm)# 将 处理器 添加到 日志器cls.logger.addHandler(sh)cls.logger.addHandler(th)# 返回日志器return cls.loggerif __name__ == '__main__':logger = GetLogger.get_logger()# 日志器应用logger.info("这是info日志信息")logger.debug("这是debug日志信息")logger.warning("这是warning日志信息")logger.error("这是error日志信息")

page:

  • __init__.py

from selenium.webdriver.common.by import By
""" 以下为项目服务器地址 """
URL = "http://localhost"""" 以下为登录模块涉及元素 配置信息"""
# 登录链接
login_link = By.PARTIAL_LINK_TEXT, "登录"
# 用户名
login_username = By.CSS_SELECTOR, "#username"
# 密码
login_pwd = By.CSS_SELECTOR, "#password"
# 验证码
login_verify_code = By.CSS_SELECTOR, "#verify_code"
# 登录按钮
login_btn = By.CSS_SELECTOR, ".J-login-submit"
# 错误提示信息
login_err_info = By.CSS_SELECTOR, ".layui-layer-content"
# 错误提示框 确定按钮
login_err_ok_btn = By.CSS_SELECTOR, ".layui-layer-btn0"
# 安全退出 按钮
login_logout_link = By.PARTIAL_LINK_TEXT, "安全退出"""" 以下数据为购物车配置数据 """
# 搜索框
cart_search = By.CSS_SELECTOR, "#q"
# 搜索按钮
cart_search_btn = By.CSS_SELECTOR, ".ecsc-search-button"
# 添加购物车 --> 跳转到详情页面
cart_add_info = By.CSS_SELECTOR, ".p-btn>a"
# 添加购物车
cart_add = By.CSS_SELECTOR, "#join_cart"
# iframe 表单名称
cart_frame_name = By.CSS_SELECTOR, "layui-layer-iframe1"
# id 属性 定义元素
cart_frame_id = By.CSS_SELECTOR, "#layui-layer-iframe1"
# 获取添加购物车结果
cart_add_result = By.CSS_SELECTOR, ".conect-title>span"
# 关闭提示窗口
cart_close_window = By.CSS_SELECTOR, ".layui-layer-close"""" 以下数据为订单页面配置数据 """
# 我的购物车
order_my_cart = By.CSS_SELECTOR, ".c-n"
# 全选
order_all = By.CSS_SELECTOR, ".checkCartAll"
# 去结算
order_account = By.CSS_SELECTOR, ".gwc-qjs"
# 收货人 备用
order_person = By.CSS_SELECTOR, ".consignee>b"
# 提交订单
order_submit = By.CSS_SELECTOR, ".Sub-orders"
# 获取提交订单结果
order_submit_result = By.CSS_SELECTOR, ".erhuh>h3"""" 以下数据为支付模块配置数据 """
# 我的订单
pay_my_order = By.PARTIAL_LINK_TEXT, "我的订单"
# 我的订单页面title 注意:此处为变量,不要By
pay_my_order_title = "我的订单"
# 立即支付
pay_now_payment = By.CSS_SELECTOR, ".ps_lj"
# 支付页面title
pay_payment_title = "订单支付-开源商城 | B2C商城 |..."
# 货到付款
pay_on_delivery = By.CSS_SELECTOR, "[src='/plugins/payment/cod/logo.jpg']"
# 确认支付
pay_confirm_payment = By.CSS_SELECTOR, ".button-confirm-payment"
# 获取支付结果
pay_payment_result = By.CSS_SELECTOR, ".erhuh>h3"
  • page_cart.py

# 导包
from time import sleep
from day11_tpshop import page
from day11_tpshop.base.base import Base
from day11_tpshop.base.get_logger import GetLogger# 获取log日志
log = GetLogger().get_logger()class PageCart(Base):# 打开首页def page_open_index(self):# 注意:由于业务问题,必须暂停2秒,否则在登录时,改变url会报错sleep(2)log.info("[page_cart]:正在打开首页")self.base_index()# 输入搜索内容 小米手机def page_input_search(self, value="小米手机"):log.info("[page_cart]:正在输入搜索内容:{}".format(value))self.base_input(page.cart_search, value)# 点击搜索按钮def page_click_search_btn(self):log.info("[page_cart]:正在点击搜索按钮")self.base_click(page.cart_search_btn)# 点击添加购物车 跳转到商品详情页def page_click_add_cart_info(self):log.info("[page_cart]:正在点击加入购物车按钮,跳转到商品详情页")self.base_click(page.cart_add_info)# 点击加入购物车def page_click_add_cart(self):log.info("[page_cart]:正在点击加入购物车按钮,弹出frame表单")self.base_click(page.cart_add)# 点击获取添加结果def page_get_text(self):# # 切换frame表单 以name属性切换 由于电脑配置问题,导致加载比较慢,不建议使用# self.switch_to_frame(page.cart_frame_name)# 以元素属性切换 推荐self.base_switch_frame(self.base_find(page.cart_frame_id))# 获取结果并返回log.info("[page_cart]:正在返回购物结果信息")return self.base_get_text(page.cart_add_result)# 关闭窗口def page_close_window(self):# 回到默认目录self.base_default_content()# 关闭操作log.info("[page_cart]:正在关闭表单弹窗")self.base_click(page.cart_close_window)# 组合业务调用方法def page_cart(self):log.info("[page_cart]:正在执行添加购物车操作")self.page_input_search()self.page_click_search_btn()self.page_click_add_cart_info()self.page_click_add_cart()
  • page_login.py

from day11_tpshop import page
from day11_tpshop.base.base import Base
from day11_tpshop.base.get_logger import GetLogger# 获取log日志器
log = GetLogger().get_logger()class PageLogin(Base):# 点击 登录链接def page_click_login_link(self):log.info("[page_login]:执行{}元素点击链接操作".format(page.login_link))self.base_click(page.login_link)# 输入用户名def page_input_username(self, username):log.info("[page_login]:对{}元素 输入用户名{}操作".format(page.login_username, username))self.base_input(page.login_username, username)# 输入密码def page_input_pwd(self, pwd):log.info("[page_login]:对{}元素 输入密码{}操作".format(page.login_pwd, pwd))self.base_input(page.login_pwd, pwd)# 输入验证码def page_input_verify_code(self, verify_code):log.info("[page_login]:对{}元素 输入验证码{}操作".format(page.login_verify_code, verify_code))self.base_input(page.login_verify_code, verify_code)# 点击 登录def page_click_login_btn(self):log.info("[page_login]:执行{}元素点击操作".format(page.login_btn))self.base_click(page.login_btn)# 获取 错误提示信息def page_get_err_info(self):return self.base_get_text(page.login_err_info)# 点击 错误提示框 确定按钮def page_click_error_alert(self):log.info("[page_login]:执行{}元素点击操作".format(page.login_err_ok_btn))self.base_click(page.login_err_ok_btn)# 判断是否登录成功def page_if_login_success(self):# 注意 一定要将找元素的结果返回,True:存在return self.base_elememt_is_exist(page.login_logout_link)# 点击 安全退出def page_click_logout_link(self):self.base_click(page.login_logout_link)# 判断是否退出成功def page_if_logout_success(self):return self.base_elememt_is_exist(page.login_link)# 组合业务方法 登录业务直接调用def page_login(self, username, pwd, verify_code):log.info("[page_login]:正在执行登录操作,用户名:{},密码:{},验证码:{}".format(username, pwd, verify_code))self.page_input_username(username)self.page_input_pwd(pwd)self.page_input_verify_code(verify_code)self.page_click_login_btn()# 组合登录业务方法 给(购物车模块、订单模块、支付模块)依赖登录使用def page_login_success(self, username="13800001111", pwd="123456", verify_code="8888"):# 点击登录链接self.page_click_login_link()log.info("[page_login]:正在执行登录操作,用户名:{},密码:{},验证码:{}".format(username, pwd, verify_code))self.page_input_username(username)self.page_input_pwd(pwd)self.page_input_verify_code(verify_code)self.page_click_login_btn()
  • page_order.py

from time import sleep
from day11_tpshop import page
from day11_tpshop.base.base import Baseclass PageOrder(Base):# 打开首页def page_click_index(self):self.base_index()# 点击 我的购物车def page_click_my_cart(self):self.base_click(page.order_my_cart)# 点击 全选复选框def page_click_all_select(self):# 判断 如果没选中 就进行点击操作if not self.base_find(page.order_all).is_selected():self.base_click(page.order_all)# 点击 去结算def page_click_account(self):self.base_click(page.order_account)# 备用 查找收货人 --> 动态 解决 收货人加载慢的问题(数据异步加载)def page_find_person(self):self.base_find(page.order_person)# 点击 提交订单def page_click_submit_order(self):self.base_click(page.order_submit)# 获取 订单提交结果def page_get_submit_result(self):return self.base_get_text(page.order_submit_result)# 组装订单业务方法def page_order(self):self.page_click_my_cart()self.page_click_all_select()self.page_click_account()# 注意:此处有一个坑,默认收货人在页面加载完成后3秒后才出现。# 解决方法一:使用sleep(5)# sleep(5)# 解决方法二:使用显示等待时长机制,查找收货人元素【推荐】# 找到收货人,说明异步加载完成,收货人信息出现,直接可以执行下一步提交订单操作self.page_find_person()self.page_click_submit_order()
  • page_pay.py

from day11_tpshop import page
from day11_tpshop.base.base import Baseclass PagePay(Base):# 点击 我的订单链接def page_click_my_order_link(self):self.base_click(page.pay_my_order)# 点击 立即支付def page_click_now_payment(self):# 必须先切换窗口self.base_switch_to_window(page.pay_my_order_title)# 点击立即支付self.base_click(page.pay_now_payment)# 点击 货到付款def page_click_pay_on_delivery(self):# 先切换窗口self.base_switch_to_window(page.pay_payment_title)# 点击货到付款self.base_click(page.pay_on_delivery)# 确认支付def page_click_payment_mode(self):self.base_click(page.pay_confirm_payment)# 获取支付结果def page_get_payment_result(self):self.base_get_text(page.pay_payment_result)# 组合支付业务方法def page_pay(self):self.page_click_my_order_link()self.page_click_now_payment()self.page_click_pay_on_delivery()self.page_click_payment_mode()

scripts:

  • test01_login.py

import unittest
from day11_TPshop项目.base.get_driver import GetDriver
from day11_TPshop项目.base.get_logger import GetLogger
from day11_TPshop项目.page.page_login import PageLogin
from day11_TPshop项目.tools.read_txt import read_txt
from parameterized import parameterized# 获取log日志器
log = GetLogger().get_logger()def get_data():arrs = []for data in read_txt("login.txt"):arrs.append(tuple(data.strip().split(",")))return arrs[1:]# 新建 登录测试类 并 继承 unittest.TestCase
class TestLogin(unittest.TestCase):# 新建 setUpClass@classmethoddef setUpClass(cls) -> None:try:# 实例化 并获取 drivercls.driver = GetDriver.get_driver()# 实例化 PageLogin()cls.login = PageLogin(cls.driver)# 点击登录链接cls.login.page_click_login_link()except Exception as e:# 截图cls.login.base_get_img()# 日志log.error("错误:{}".format(e))# 新建 tearDownClass@classmethoddef tearDownClass(cls) -> None:# 关闭driver驱动对象GetDriver.quit_driver()# 新建 登录测试方法@parameterized.expand(get_data())def test_login(self, username, pwd, verify_code, expect_result, status):try:# 调用 登录业务方法self.login.page_login(username, pwd, verify_code)# 判断是否为正向if status == "true":# 断言是否登录成功try:self.assertTrue(self.login.page_if_login_success())except Exception as e:# 截图self.login.base_get_img()# 日志log.error("出错了:{}".format(e))# 点击 安全退出self.login.page_click_logout_link()# 点击 登录链接self.login.page_click_login_link()# 逆向用例else:# 获取错误提示信息msg = self.login.page_get_err_info()print("msg:", msg)try:self.assertEqual(msg, expect_result)except Exception as e:# 截图self.login.base_get_img()# 日志log.error("出错了:{}".format(e))# 点击错误提示框 确定按钮self.login.page_click_error_alert()except Exception as e:# 截图self.login.base_get_img()# 日志log.error("出错了:{}".format(e))
  • test02_cart.py(代码略)

  • test03_order.py(代码略)

  • test04_pay.py(代码略)

run:

  • run_main.py

# 导包
import unittest
import time
from day11_tpshop.tools.HTMLTestRunner import HTMLTestRunner# 定义测试套件
suite = unittest.defaultTestLoader.discover("../scripts/")# 报告生成目录及文件名称
dir_path = "../report/{}.html".format(time.strftime("%Y_%m_%d %H_%M_%S"))
# 获取文件流并调用run运行,生成测试报告
with open(dir_path, "wb") as f:HTMLTestRunner(stream=f, title="TpShop商城自动化测试报告", description="操作系统:Win10")

tools:

  • HTMLTestRunner.py

  • HTMLTestRunnerCN.py

  • read_text.py

def read_txt(filename):filepath = "../data/"+filenamewith open(filepath, "r", encoding="utf-8") as f:return f.readlines()"""问题:读出来的不是预期需要的格式
"""if __name__ == '__main__':print(read_txt("calc.txt"))print("--" * 60)arrs1 = []for data in read_txt("calc.txt"):arrs1.append(tuple(data.strip().split(",")))print("arrs1为:", arrs1)  # [(), ()]arrs2 = []for data in read_txt("calc.txt"):arrs2.append(data.strip().split(","))print("arrs2为:", arrs2[1::])  # [[], []]
  • read_json.py

# 导包
import jsondef read_json(filename):filepath = "../data/"+filename# 获取文件流 并调用loadwith open(filepath, "r", encoding="utf-8") as f:return json.load(f)"""问题:需求格式:[(), ()] 或 [[], []]解决:1、新建空列表 arrs = []2、读取现有的 json 值,存放到列表中
"""if __name__ == '__main__':print(read_json("login.json"))print("--" * 60)# 新建空列表arrs1 = []for data1 in read_json("login.json").values():# print(data)arrs1.append((data1.get("username"),data1.get("password"),data1.get("verify_code"),data1.get("expect")))print(arrs1)  # [(), ()]arrs2 = []for data2 in read_json("login.json").values():arrs2.append([data2.get("username"),data2.get("password"),data2.get("verify_code"),data2.get("expect")])print(arrs2)  # [[], []]

data:

  • login.txt(内容略)

  • login.json(内容略)

image: 截图保存的文件夹(内容略)

log: 日志收集保存的文件夹(内容略)

report: 测试报告生成的文件夹(内容略)


最后感谢每一个认真阅读我文章的人,看着粉丝一路的上涨和关注,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走

面试资料

我们学习软件测试必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。

上面是我整理的配套资源,这些资源对于软件测试的的朋友来说应该是最全面最完整的备战仓库,为了更好地整理每个模块,我也参考了很多网上的优质博文和项目,力求不漏掉每一个知识点,很多朋友靠着这些内容进行复习,拿到了BATJ等大厂的offer,这个仓库也已经帮助了很多的软件测试的学习者,希望也能帮助到你。

【Web UI自动化测试】Web UI自动化测试之PO篇(全网最全)相关推荐

  1. 【Web UI自动化测试】Web UI自动化测试之日志收集篇(全网最全)

    本文大纲截图: 1.日志介绍[文末免费分享自动化测试学习资源] 日志: 用于记录系统运行时的信息,对一个事件的记录,也称为Log. 日志作用: 1)调试程序 2)了解系统程序运行的情况是否正常 3)系 ...

  2. 【Web UI自动化测试】Web UI自动化测试之框架篇(全网最全)

    本文大纲截图: UnitTest框架: PyTest框架: 框架: 框架英文单词 framework,为解决一类事情的功能的集合.需要按照框架的规定(套路)去书写代码. 一.UnitTest框架介绍[ ...

  3. 自动化测试之PO模型

    一. PO模型介绍 在自动化中,Selenium自动化测试中有一个名字经常被提及PageObject(思想与面向对象的特征相 同),通常PO模型可以大大提高测试用例的维护效率 二.PO的核心要素 1. ...

  4. 【30天学会接口自动化测试】接口自动化测试之框架设计(五)

    整理了一些软件测试方面的资料.面试资料(接口自动化.web自动化.app自动化.性能安全.测试开发等),有需要的小伙伴可以文末加入我的学习交流qun,无套路自行领取~ 如果有100个测试用例,重复的去 ...

  5. 【30天学会接口自动化测试】接口自动化测试之实际项目做接口测试(6)

    整理了一些软件测试方面的资料.面试资料(接口自动化.web自动化.app自动化.性能安全.测试开发等),有需要的小伙伴可以文末加入我的学习交流qun,无套路自行领取~ 1.从实际项目出发分析测试结果处 ...

  6. python 接口自动化测试_python接口自动化测试之接口数据依赖

    作者:泰斯特test 链接:https://juejin.im/post/5cc11f6be51d45401f566d14 在做自动化测试时,经常会对一整套业务流程进行一组接口上的测试,这时候接口之间 ...

  7. 玩玩自动化测试之selenium篇

    现如今社会科技发展太快了,纯功能点点点已经落后别人好几条街了,所以为了让自己多点职业生涯年限,得挺起肩,傲起头.自动化测试,其本质是用代码程序测试程序,所以其实第一步应该学好编程语言,后再自己开发自动 ...

  8. Windows下Python3+nose+appium自动化测试之Android篇

    [本文出自天外归云的博客园] 简介 以下用来做自动化测试的这款app叫最爱抓娃娃,以后会改名为网易抓娃娃. 下文提到的appiumier项目里会包含用来测试的apk包以及自动化测试代码. 先说一个坑 ...

  9. appium java类库下载_Appium移动自动化测试之Java篇

    2.新建一个java project,[File]-->[New]-->[Project],[Java Project]-->[Next],输入工程名称Appium,点击[Finis ...

最新文章

  1. 目标检测--Light-Head R-CNN: In Defense of Two-Stage Object Detector
  2. 3.菜鸟教你一步一步开发 web service 之 axis 服务端创建
  3. 土木工程真的这么可怕吗?
  4. 转【微信小程序 四】二维码生成/扫描二维码
  5. 使用 MarkDown DocFX 升级 Rafy 帮助文档
  6. keepalived的安装与添加服务
  7. ACM - 第6章 数据结构基础(2)
  8. shell 倒数第n列_【零基础学云计算】Shell编程之正则表达式(三)
  9. Spring容器创建流程——总结
  10. 【java】System.arraycopy为什么快
  11. Dreamweaver CS5.5+PhoneGap移动开发环境搭建
  12. 秒杀系统设计中的业务性思考
  13. WDS+MDT网络部署操作系统
  14. 网友对各种杀软的评价诗歌
  15. [译]露天矿山道路设计指南:第一章
  16. raid5磁盘阵列数据恢复方法_服务器数据恢复步骤_存储结构介绍
  17. EV充电插头相关知识学习了解
  18. Android上传图片的方式
  19. elasticsearch7.5.0 集群部署
  20. 从零构建知识图谱(技术、方法与案例)-第一章:知识图谱概览

热门文章

  1. 招聘需求 视觉工程师
  2. com.android.ide.common.signing.KeytoolException: Failed to read key AndroidDebugKey from store
  3. MATLAB画图-plot-线形、颜色、数据点形状的选择
  4. golang实现单点登录
  5. 星座图中格雷映射及其实现
  6. R6034问题的解决
  7. 解决win7提示不是正版的问题
  8. 采用AT89C2051的智能时钟
  9. android span图片居中,Android ImageSpan的图文居中对齐
  10. 201871010123-吴丽丽《面向对象程序设计(java)》第二周学习总结