测试技能整理HM-UI自动化测试

自动化测试理论

UI:User Interface(⽤户接⼝-⽤户界⾯),主要包括:app、web
UI自动化测试:使用工具或代码执行用例的过程
什么样的项⽬适合做自动化:
1、需要回归测试项⽬(甲方自营项目、金融、电商)
2、需求变动不频繁:稳定的模块
3、项目周期⻓的项⽬:(甲⽅⾃营项⽬、6个⽉以上的外包)

自动化测试工具及环境

工具说明

QTP:商业、收费、⽀持UI
robot Framework:python扩展库、使⽤封装好的关键字驱动、半代码⽔平、⽀持UI
selenium:开源、免费、主流⽀持UI

selenium介绍

在这里插入图片描述

提示:
1、selenium-grid可以做分布式(批量在不同平台中运⾏⽤例),⾃动化⽤例较多时、或测试不
同浏览器在不同平台运⾏时可以使⽤。
2、对⻚⾯元素实施⾃动化测试,主要使⽤:webdriver

环境搭建

所需环境: pthon解释器+pycharm+selenium+浏览器+浏览器驱动
selenium

pip install selenium

浏览器驱动

chrome: http://npm.taobao.org/mirrors/chromedriver/
提示:浏览器驱动⼤版本必须和浏览器版本⼀致

使用:
windows:
1、解压下载的驱动,获取到chromedriver.exe
2、将chromedriver.exe复制到python.exe所在⽬录即可(避免再次将chromedrver.exe添加path变量)

元素定位

什么是元素定位?
通过代码调⽤⽅法查找元素

元素定位⽅法
1、id
2、name
3、class
4、tag_name
5、link_text
6、partial_link_text
7、xpath
8、css

步骤

1、打开⾕歌浏览器
2、输⼊url
3、找元素及操作
4、关闭浏览器

from time import sleep
from selenium import webdriver
# 1、打开⾕歌浏览器(实例化浏览器对象)
driver = webdriver.Chrome()
# 2、输⼊url
driver.get("http://tpshop-test.itheima.net/Home/user/login.html")
# 3、找元素及操作
# 4、关闭浏览器
sleep(3)
driver.quit()

id定位

⽅法: driver.find_element_by_id(“id值”)
前置: 标签必须有id属性
输⼊⽅法: 元素.send_keys(“内容”)

from time import sleep
from selenium import webdriver
# 1、获取浏览器
driver = webdriver.Chrome()
# 2、打开url
driver.get("file:///Users/lgy/Documents/fodder/web/%E6%B3%A8%E5%86%8CA.html
")
# 3、查找操作元素
# ⽤户名 -> id ->driver.find_element_by_id("id")
# 元素.send_keys()输⼊⽅法
driver.find_element_by_id("userA").send_keys("admin")
# 密码
driver.find_element_by_id("passwordA").send_keys("123456")
# 4、关闭浏览器
sleep(3)
driver.quit()

name定位

⽅法: driver.find_element_by_name(“name属性值”)
前置: 标签必须name属性
特点: 当前⻚⾯可以重复
提示: 由于name属性值可以重复,所以使⽤时需要查看是否为唯⼀。

class定位

⽅法: driver.find_element_by_class_name(“class属性值”)
前置: 标签必须有class属性
特点: class属性值可以有多个值
在这里插入图片描述
说明:如果标签有多个class值,使⽤任何⼀个都可以。如:c1

tag_name定位

说明:根据的标签名进⾏定位
⽅法: driver.find_elemet_by_tag_name(“标签名”)
提示: 如果⻚⾯存在多个相同标签,默认返回第⼀个。

link_text定位

说明: 根据链接⽂本(a标签)定位
⽅法: driver.find_element_by_link_text(“链接⽂本”)
特点: 传⼊的链接⽂本,必须全部匹配,不能模糊

partial_link_text定位

说明: 根据链接⽂本(a标签)定位
⽅法: driver.find_element_by_partial_link_text(“链接⽂本”)
特点: 传⼊的链接⽂本,⽀持模糊匹配(传⼊局部⽂字)

扩展-查找⼀组元素

说明:返回列表格式,要使⽤需要添加下标或遍历。
⽅法: driver.find_elements_by_xxxx(),
提示: ⼋⼤元素定位⽅法,都可以使⽤⼀组元素定位,如果没有搜索到符合标签,返回空
列表。

在这里插入图片描述

xpath

说明:xpath是xml path简称,使⽤标签路径来定位。
绝对路径:从根⽬录开始,逐级查找标签。
在这里插入图片描述
相对路径:从任意层级开始,查找标签
在这里插入图片描述
策略(⽅法):

1、路径
2、属性
3、属性与逻辑(多个属性)
4、属性与层级(路径)

⽅法: driver.find_element_by_xpaht(“表达式”)
在这里插入图片描述

# 绝对路径
el =
driver.find_element_by_xpath("/html/body/form/div/fieldset/center/p[1]/input
")
el.send_keys("admin")
sleep(2)
# 清除内容
el.clear()
# 相对路径
driver.find_element_by_xpath("//p[1]/input").send_keys("123")

属性
单属性: // * [@属性名=‘属性值’]
多属性: // * [@属性名=‘属性值’ and @属性名=‘属性值’]
提示:可以使⽤任何属性。
层级与属性
说明: 如果元素现有的属性不能唯⼀匹配,需要结合层级使⽤
语法:
//⽗标签/⼦标签 必须为直属⼦级
//⽗标签[@属性=‘值’]//后代标签 ⽗和后代之间可以跨越元素
扩展
根据显示⽂本定位: //*[text()=‘⽂本值’]
属性值模糊匹配: // * [contains(@属性名,‘属性部分值’)]

在这里插入图片描述

from time import sleep
from selenium import webdriver
# 1、获取浏览器
driver = webdriver.Chrome()
# 2、打开url
driver.get("http://hmshop-test.itheima.net/")
# 3、查找操作元素
# 点击登录链接 ⽂本
driver.find_element_by_xpath("//*[text()='登录']").click()
# 输⼊⽤户名 属性
driver.find_element_by_xpath("//*[@placeholder='⼿机号/邮
箱']").send_keys("13600001111")
# 密码 包含
driver.find_element_by_xpath("//*
[contains(@placeholder,'密')]").send_keys("123456")
# 验证码 多属性
driver.find_element_by_xpath("//*[@placeholder='验证码' and
@name='verify_code']").send_keys("8888")
# 登录按钮 层级
driver.find_element_by_xpath("//*[@class='login_bnt']/a").click()
# 4、关闭浏览器
sleep(3)
driver.quit()

css选择器

说明:css选择器是html查找元素的⼯具
策略:
1、id选择器
2、类选择器
3、标签选择器
4、属性选择器
5、层级选择器
id选择器
语法: #id属性值
前置: 标签必须id属性
类选择器
语法: .class属性值
前置: 标签必须class属性
标签选择器
语法: 标签名
提示: 注意标签是否在⻚⾯中唯⼀,否则返回单个或所有
属性选择器
语法: [属性名=‘属性值’]
说明: 标签任意属性都可以
案例
在这里插入图片描述

# ⽤户名 id选择->#id属性值
driver.find_element_by_css_selector("#userA").send_keys("admin")
# 密码 属性选择器->[属性名='属性值']
driver.find_element_by_css_selector("[name='passwordA']").send_keys("123456")
# 电话 类选择器->.class属性值
driver.find_element_by_css_selector(".telA").send_keys("18600000000")
# 确定 标签选择器-标签名
sleep(2)
driver.find_element_by_css_selector("button").click()

层级选择器
⽗⼦关系: 选择器>选择器 如: #p1>input
后代关系: 选择器 选择器 如: #p1 input
提示: 选择器使⽤任何⼀种css选择器(id选择器、类选择器、属性选择器、标签选
择器)都可以

find_element

说明: ⼋种元素定位⽅法底层使⽤的查找元素⽅法都是find_element,通过By不同的值区
分定位⽅式
学习此⽅法⽬的: 后期为了查找元素⽅法的封装

"""
 ⽬标:讲解find_element使⽤
 场景:后期项⽬封装中,使⽤元素查找⽅法
 ⽬的:对后期封装元素查找⽅法
"""
driver.find_element(By.ID,"userA").send_keys("admin")
driver.find_element(By.NAME,"passwordA").send_keys("123456")
driver.find_element(By.CLASS_NAME,"telA").send_keys("18600000000")
sleep(2)
driver.find_element(By.TAG_NAME,"button").click()

在这里插入图片描述

结论:
1、⾸推css定位,原因执⾏速度快。
①如果有ID属性,使⽤#id
②没有id属性,使⽤其他有的属性(能代表唯⼀的属性)
③如果属性都带不了唯⼀,使⽤层级
2、如果css解决不了,使⽤xpath。

元素操作

1、操作⽅法
2、获取⽅法

常用操作方法

元素=driver.find_element()
点击:元素.click()
输⼊:元素.send_keys(内容)
清空:元素.clear()

获取元素信息

⽅法
获取⼤⼩: 元素.size
获取⽂本: 元素.text
获取属性: 元素.get_attribute(‘属性名’)
元素是否可⻅: 元素.is_displayed()
元素是否可⽤: 元素.is_enabled()
元素是否选中: 元素.is_selected()

# 获取⼤⼩ 元素.size
user = driver.find_element(By.CSS_SELECTOR,"#userA").size
print("⽤户名输⼊框的⼤⼩:",user)
# 获取内容 元素.text
a_text = driver.find_element(By.TAG_NAME,"a").text
print("第⼀个a标签的⽂本:",a_text)
# 获取属性 超连接地址
a_href = driver.find_element(By.TAG_NAME,"a").get_attribute("href")
print("第⼀个a标签的链接:",a_href)
# 判断span标签是否可⻅ 元素.is_displayed
span = driver.find_element(By.TAG_NAME,"span").is_displayed()
print("span是否可⻅:",span)
# 判断取消按钮是否可⽤ is_enabled
btn_is_enabled = driver.find_element(By.CSS_SELECTOR,"#cancelA").is_enabled()
print("取消按钮是否可⽤:",btn_is_enabled)
# 旅游是否选中 is_selected
is_selected = driver.find_element(By.CSS_SELECTOR,"#lyA").is_selected()
print("旅游是否被选中:",is_selected)

在这里插入图片描述

浏览器操作

浏览器常用api

在这里插入图片描述
在这里插入图片描述

# 最⼤化浏览器
driver.maximize_window()
sleep(3)
# 设置窗⼝⼤⼩
driver.set_window_size(500,700)
sleep(3)
driver.set_window_position(0,500)
sleep(3)
# 点击新浪
driver.find_element_by_partial_link_text("新浪").click()
sleep(3)
# 后退
driver.back()
sleep(3)
# 前进
driver.forward()
sleep(3)
driver.refresh()

浏览器常用获取信息api

在这里插入图片描述
重点:
1、close关闭当前焦点所在窗⼝
2、quit关闭的是浏览器
3、启动那个窗内⼝,默认焦点就在那个窗⼝。如果需要切换到别的窗⼝,需要调⽤api⽅法切
换。
在这里插入图片描述

# 1、获取浏览器
driver = webdriver.Chrome()
# 2、打开url
driver.get("file:///Users/lgy/Documents/fodder/web/Register.html")
# 最⼤化浏览器
driver.maximize_window()
# 获取当前窗⼝标题
print("当前窗⼝title:",driver.title)
# 获取当前窗⼝url
print("当前窗⼝url:",driver.current_url)
sleep(3)
driver.find_element_by_partial_link_text("注册A⽹⻚").click()
# 获取当前窗⼝标题
print("当前窗⼝title:",driver.title)
# 获取当前窗⼝url
print("当前窗⼝url:",driver.current_url)
sleep(3)
# 关闭当前窗内⼝
driver.close()
# 4、关闭浏览器
sleep(3)
driver.quit()

页面交互

下拉框

在这里插入图片描述
方式:
1、使⽤css或xpth (推荐)
2、使⽤专属Select类
方式1:

# 点击⼴州
driver.find_element(By.CSS_SELECTOR, "[value='gz']").click()
sleep(2)
driver.find_element(By.CSS_SELECTOR, "[value='sh']").click()
sleep(2)
driver.find_element(By.CSS_SELECTOR, "[value='bj']").click()

方式2:

from selenium.webdriver.common.by import By
from selenium.webdriver.support.select import Select
# 使⽤Select类来实现
# 1、定位下拉框元素 select
el = driver.find_element(By.CSS_SELECTOR,"#selectA")
# 2、实例化Select对象
select = Select(el)
# 3、使⽤下标定位⼴州
select.select_by_index(2)
sleep(2)
# 使⽤value定位上海
select.select_by_value("sh")
# 使⽤⽂本定位 北京
sleep(2)
select.select_by_visible_text("A北京")

弹窗

如果⻚⾯操作过程中,有弹窗出现,不处理,⽆法继续对⻚⾯操作
弹窗类型?
1、js原⽣弹窗(警告框、输⼊框、提示框)必须处理
2、开发使⽤标签⾃定义弹窗效果 (不⽤处理,正常操作即可。)
处理:
1、获取弹窗对象
2、点⽤同意或取消⽅法

# 点击弹窗
driver.find_element(By.ID,"alerta").click()
sleep(2)
# 获取弹窗对象
el = driver.switch_to.alert
# 处理弹窗 同意/取消
# el.dismiss() # 取消
# print("弹出⽂本:",el.text)
el.accept() # 同意
sleep(2)
# 输⼊⽤户名
driver.find_element(By.CSS_SELECTOR,"#userA").send_keys("admin")

滚动条

步骤:
1、定义js语句
2、调⽤执⾏js⽅法

# js -> 向下滑动10000像素
# js_down = "window.scrollTo(0,10000)"
# 动态执⾏滑倒底部 向下滑动滚动条⾼度
# js(0,10000) 第⼀个0为⽔平滚动条
js_down = "window.scrollTo(0,document.body.scrollHeight)"
# 执⾏js⽅法
driver.execute_script(js_down)
sleep(2)
# js—> 向上
js_top = "window.scrollTo(0,0)"
driver.execute_script(js_top)

鼠标操作

在这里插入图片描述
1、双击⽅法
2、右击⽅法
3、悬停
4、拖拽
在这里插入图片描述

from selenium.webdriver import ActionChains
# 获取ActionChains对象
action = ActionChains(driver)
# 练习 1
# 查找注册按钮
el = driver.find_element(By.CSS_SELECTOR,"button")
sleep(2)
# 调⽤悬停⽅法
action.move_to_element(el).perform()
# # 练习2
# username = driver.find_element(By.CSS_SELECTOR,"#userA")
# # 右击
# action.context_click(username).perform()
# 练习3
username = driver.find_element(By.CSS_SELECTOR,"#userA")
username.send_keys("admin")
sleep(3)
# 双击
action.double_click(username).perform()
# 拖拽
action = ActionChains(driver)
div1 = driver.find_element(By.CSS_SELECTOR, "#div1")
div2 = driver.find_element(By.CSS_SELECTOR, "#div2")
action.drag_and_drop(div1, div2).perform()

高级API

代码执⾏过程中,第⼀次未找到元素,先不抛出异常。激活等待时间,在等待过程中如果找到元素
就执⾏
为什么要等待?
由于⽹络或配置原因,导致元素未加载出来,⽽代码已执⾏,会触发异常。
元素等待类型
1、隐式等待
2、显示等待
3、强制等待 -->time.seep(秒)

隐式元素等待
说明: 针对全部元素⽣效
⽅法: driver.implicitly_wait(秒)
提示:在项⽬中,如果未封装⾃动化框架时,推荐使⽤

显示等待
说明: 针对单个元素⽣效,可以修改查找频率和超时时间。
特点: 查找并返回元素

from selenium.webdriver.support.wait import WebDriverWait
# 2、显示等待 -> 返回查找到的元素
el = WebDriverWait(driver,10,0.5).until(lambda x:
x.find_element(By.CSS_SELECTOR,"#userAA"))
el.send_keys("admin")

强制等待
语法: sleep(10)
提示: 执⾏到这句必须等待10秒,不灵活。
示例

from time import sleep
sleep(10)

在这里插入图片描述
在这里插入图片描述

操作frame框架的元素

frame(iframe)标签作⽤–是什么
在⻚⾯中加载另⼀个⻚⾯

为什么处理iframe(frane)?
在这里插入图片描述
焦点默认在启动⻚⾯,如果不出处理iframe,⽆法操作iframe嵌⼊的⻚⾯元素
如何处理?

1、切换到iframe driver.switch_to.frame(iframe元素)
2、操作元素
3、回到默认⻚⾯ driver.switch_to.default_content()

在这里插入图片描述

# 获取注册A iframe元素
A = driver.find_element(By.CSS_SELECTOR, "#idframe1")
# 1、切换到A
driver.switch_to.frame(A)
# 2、注册A操作
driver.find_element(By.CSS_SELECTOR,"#userA").send_keys("admin")
# 3、回到默认⽬录 注册时例.html
driver.switch_to.default_content()
# 4、获取注册B iframe元素
B = driver.find_element(By.CSS_SELECTOR, "#idframe2")
# 5、切换到B
driver.switch_to.frame(B)
# 6、注册B操作
driver.find_element(By.CSS_SELECTOR,"#userB").send_keys("admin")

切换多窗口

在这里插入图片描述
selenium默认启动时,所有的焦点在启动窗⼝,那么意味着⽆法操作其他窗⼝的标签
步骤:
1、获取窗⼝句柄 driver.window_handles
2、使⽤句柄切换窗⼝ driver.switch_to.widnow(handle)
句柄:窗⼝的唯⼀标识符。

"""
 需求:
 1、打开注册示例⻚⾯
 2、点击注册A⽹⻚链接
 3、填写注册A⽹⻚内容
"""
print("操作之前所有窗⼝的句柄:", driver.window_handles)
driver.find_element(By.LINK_TEXT, "注册A⽹⻚").click()
handles = driver.window_handles
print("操作之后所有窗⼝的句柄:", handles)
# 重点:切换窗⼝
driver.switch_to.window(handles[1])
# 填写注册A⽹⻚ ⽤户名
driver.find_element(By.CSS_SELECTOR, "#userA").send_keys("admin")

多窗⼝之间切换⼯具封装

def switch_window(title):
 # 1、获取所有窗⼝句柄
 handels = driver.window_handles
 # 2、遍历句柄进⾏切换
 for handel in handels:
 # 操作
 driver.switch_to.window(handel)
 # 获取当前窗⼝title 并且 判断是否⾃⼰需要的窗⼝
 if driver.title == title:
 # 操作代码
 return "已找到{}窗⼝,并且已切换成功".format(title)
 title_A = "注册A"
title_B = "注册B"
# 打开注册A和注册B⽹⻚
driver.find_element(By.LINK_TEXT, "注册A⽹⻚").click()
driver.find_element(By.LINK_TEXT, "注册B⽹⻚").click()
# 填写注册A⽹⻚ ⽤户名
switch_window(title_A)
driver.find_element(By.CSS_SELECTOR, "#userA").send_keys("admin")
switch_window(title_B)
driver.find_element(By.CSS_SELECTOR, "#userB").send_keys("admin")

截图

driver.get_screenshot_as_file(“xxx.png”)

扩展-图⽚命名添加时间戳
在这里插入图片描述

driver.get_screenshot_as_file(“error_{}.png”.format(time.strftime(“%Y_%m_%d
%H_%M_%S”)))

验证码处理

1、去除验证码
2、使⽤万能验证码
3、使⽤图⽚识别技术(识别效率低)
4、使⽤cookie

cookie

由服务器⽣成,存储在客户端的登录凭证
1、获取cookie # 获取所有driver.get_cookies()
2、添加cookie # driver.add_cookie(data)

data = {“name”:“BDUSS”,“value”:“由于安全问题,暂时删除。”}

PO模式

PO:Page Object(⻚⾯对象),将⾃动化涉及的⻚⾯或模块封装成对象

解决问题;
1、代码复⽤性
2、便于维护(脚本层与业务分离)-- 如果元素信息发⽣变化了,也不⽤去修改脚本

PO如何做

Base层:
存放所有⻚⾯公共⽅法
Page层:
基于⻚⾯或模块单独封装当前⻚⾯要操作的对象
Script层:
脚本层+unittest

⾮PO模式代码实现

class TestLogin(unittest.TestCase):
def setUp(self) -> None:
 self.driver = webdriver.Chrome()
 self.driver.maximize_window()
 self.driver.get("http://hmshop-test.itheima.net/Home/user/login.html")
 self.driver.implicitly_wait(10)
 def tearDown(self) -> None:
 sleep(5)
 self.driver.quit()
 def test01_login(self):
 # 输⼊⽤户名
 
self.driver.find_element_by_css_selector("#username").send_keys("13600001111")
 # 输⼊密码
 self.driver.find_element_by_css_selector("#password").send_keys("123456")
 # 输⼊验证码
 self.driver.find_element_by_css_selector("#verify_code").send_keys("8888")
 # 点击登录
 self.driver.find_element_by_css_selector(".J-login-submit").click()

在这里插入图片描述

PO设计

结构
base: 存放所有Page页面公共方法
page: 将页面封装为对象
script: 测试脚本
案例(登录):
base: 分析要实现页面公共方法

"""
Base类:存放所有Page页面公共操作方法!
"""
from selenium.webdriver.support.wait import WebDriverWait
class Base:
def __init__(self, driver):
self.driver = driver
# 查找元素
# 输入方法
# 点击方法
# 获取文本值方法

base实现

class Base:
def __init__(self, driver):
self.driver = driver
# 查找元素
def base_find(self, loc, timeout=10, poll_frequency=0.5):
# 显示等待 -> 查找元素 loc = (By.ID,"userA")
return WebDriverWait(self.driver, timeout,
poll_frequency).until(lambda x: x.find_element(loc[0], loc[1]))
# 输入方法
def base_input(self, loc, value):
# 1、获取元素
el = self.base_find(loc)
# 2、清空操作
el.clear()
# 3、输入内容
el.send_keys(value)
# 点击方法
def base_click(self, loc):
self.base_find(loc).click()
# 获取文本值方法
def base_get_text(self, loc):
return self.base_find(loc).text

page结构搭建

"""
模块名:page_模块单词
类名:大驼峰将模块移植进来,去掉下划线和数字。
方法:自动化测试当前页面要操作那些元素,就封装那些方法
"""
class PageLogin:
# 输入用户名
def __page_username(self):
pass
# 输入密码
def __page_pwd(self):
pass
# 输入验证码
def __page_verify_code(self):
pass
# 点击登录按钮
def __page_click_login_btn(self):
pass
# 获取昵称
def page_get_nickname(self):
pass
# 组合业务方法 (强调:测试业务成调用此方法,便捷。)
def page_login(self):
pass

配置信息整理

from selenium.webdriver.common.by import By
# 用户名
username = (By.CSS_SELECTOR, "#username")
# 密码
pwd = By.CSS_SELECTOR, "#password"
# 验证码
verify_code = By.CSS_SELECTOR, "#verify_code"
# 登录按钮
login_btn = By.CSS_SELECTOR, ".J-login-submit"
# 昵称
nick_name = By.CSS_SELECTOR, ".userinfo"
# 提示:nick_name = By.CLASS_NAME, ".userinfo" == (By.CLASS_NAME,
".userinfo")

page实现

class PageLogin(Base):
# 输入用户名
def __page_username(self, value):
self.base_input(username, value)
# 输入密码
def __page_pwd(self, value):
self.base_input(pwd, value)
# 输入验证码
def __page_verify_code(self, value):
self.base_input(verify_code, value)
# 点击登录按钮
def __page_click_login_btn(self):
self.base_click(login_btn)
# 获取昵称
def page_get_nickname(self):
return self.base_get_text(nick_name)
# 组合业务方法 (强调:测试业务成调用此方法,便捷。)
def page_login(self, phone, password, code):
self.__page_username(phone)
self.__page_pwd(password)
self.__page_verify_code(code)
self.__page_click_login_btn()

scirpt实现

import unittest
from selenium import webdriver
from page.page_login import PageLogin
class TestLogin(unittest.TestCase):
def setUp(self) -> None:
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.get("http://hmshoptest.itheima.net/Home/user/login.html")
self.login = PageLogin(self.driver)
def tearDown(self) -> None:
self.driver.quit()
def
test01_login(self,phone="13600001111",password="123456",code="8888"):
# 调用登录业务
self.login.page_login(phone,password,code)
# 断言
nickname = self.login.page_get_nickname()
print("nickname:", nickname)

数据驱动

理论回顾
什么是数据驱动?
以测试数据驱动用例执行(测试数据和代码分离)
为什么要数据驱动?
便于维护(维护的焦点从代码转到测试数据)
数据驱动如何操作?
1、编写数据存储文件
2、编写读取数据工具
3、使用参数化引用

实际操作

步骤1、编写数据存储文件
口诀:
1、新建json文件,在文件中编写一个{}
2、有几个模块,写几个Key,值为列表
3、列表中参数化数据有几组,就写几个{}
3、每个{}中组成->说明+参数数据+预期结果

{
"login": [
{
"desc":"登录成功",
"phone": "13600001111",
"password": "123456",
"code": "8888",
"expect_text": "13600001111"
}
]
}

步骤2、读取工具封装

def read_json(filename,key):
filepath = os.path.dirname(__file__) + os.sep + "data" + os.sep +
filename
arr = []
with open(filepath,"r",encoding="utf-8") as f:
for data in json.load(f).get(key):
arr.append(tuple(data.values())[1:])
return arr

步骤3、参数化引用

import unittest
from time import sleep
from parameterized import parameterized
from selenium import webdriver
from page.page_login import PageLogin
from util import read_json
class TestLogin(unittest.TestCase):
def setUp(self) -> None:
self.driver = webdriver.Chrome()
self.driver.maximize_window()
self.driver.get("http://hmshoptest.itheima.net/Home/user/login.html")
self.login = PageLogin(self.driver)
ddd
def tearDown(self) -> None:
self.driver.quit()
@parameterized.expand(read_json("login.json", "login"))
def test01_login(self, phone, password, code, expect_text):
try:
# 调用登录业务
self.login.page_login(phone, password, code)
# 断言
nickname = self.login.page_get_nickname()
print("nickname:", nickname)
self.assertEqual(nickname, expect_text)
except Exception as e:
print("错误!",e)

APP测试相关环境

工具说明

在这里插入图片描述
app自动化执行原理
在这里插入图片描述
app类型(技术)
在这里插入图片描述

环境搭建

所需环境
jdk
android-sdk
appium
模拟器
1、Jdk安装
说明:为什么要安装jdk?
1、安卓应用或开发工具是使用java语言开发,必须使用jdk
2、android-sdk
说明:android开发工具包
1、解压到指定目录
2、将目录添加到path中

1、新建环境变量:ANDROID_HOME=D:\Android\sdk (这里为安装目录)
2、添加path路径,在Path中添加:%ANDROID_HOME%\tools;%ANDROID_HOME%\platform-tools;
提示:tools有查看元素工具,我们必须使用;platform-tools是adb命令工具所在目 录。

3、appium安装
说明: 需要安装appium服务端程序和python中调用的api库
服务端:
作用:将脚本发送给手机
安装:双击安装程序 appium-desktop-setup-1.8.0.exe ,一直到完成即可。
python的appium. api库
作用:自动化测试使用api
安装: pip install Appium-Python-Client==1.2.0
4、模拟器
说明:安卓手机
安装: 雷电、mumu、夜神,默认安装完成即可

adb工具

说明:通过电脑,操作android系统的工具

adb工作原理
在这里插入图片描述
adb命令
获取包名和启动名
包名: 一个安卓应用的唯一标识符,操作那个应用需要依赖包名
启动名: 应用中界面标识符,允许重复。

1、mac/linux: adb shell dumpsys window | grep usedApp
2、windows: adb shell dumpsys window | findstr usedApp

在这里插入图片描述
上传和下载命令
上传: adb push 路径\xxx.txt /sdcard
下载: adb pull /sdcard/xxx.txt 本地文件夹路径
启动时间命令
命令: adb shell am start -W 包名/启动名
在这里插入图片描述
注意:查看时间 一般要冷启动(应用程序没有启动)
冷启动:应用程序未启动
热启动:应用程序已启动在后台或当前页面

查看日志

命令: adb logcat > d:\xxx.log
提示: 对app操作时,要开启日志,记录app操作的步骤和异常。
其他常用命令
在这里插入图片描述
提示:
1、adb start-server正常不需要手动启动,自动启动adb.exe进程。当应用进程死机,
需要执行杀服务,杀完后需要执行命令启动。
2、adb connect ip:端口 正常不要手动连接,系统会自动连接。如果执行adb devices
没有看到设备列表,需要手动 连接。

查看元素定位信息

为什么要查看元素信息?
说明:自动化测试就是查找元素操作元素,要查找元素,就需要根据元素的信息来查找(id、
class、text、…)

如何查找?
使用:android SDK 自带工具:uiautomatorviewer工具

如何使用?
1、启动:
在这里插入图片描述
在这里插入图片描述
2、截屏查看
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

基础操作api

前置:必须启动appium服务、模拟器

from appium import webdriver
# 定义字典变量
desired_caps = {}
# 字典追加启动参数
desired_caps["platformName"] = "Android"
# 注意:版本号必须正确
desired_caps["platformVersion"] = "7.1.1"
# android不检测内容,但是不能为空
desired_caps["deviceName"] = "192.168.56.101:5555"
desired_caps["appPackage"] = "com.android.settings"
desired_caps["appActivity"] = ".Settings"
# 设置中⽂
desired_caps["nicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
# 获取driver
driver = webdriver.Remote("http://127.0.0.1:4723/wd/hub", desired_caps)

基础api

启动应用

⽅法: driver.start_activity(包名,启动名)
说明:appium⽀持夸应⽤,可以在操作应⽤中切换到B应⽤

获取当前包名、启动名

⽅法
当前应⽤包名:driver.current_package
当前应⽤启动名:driver.current_activity

"""
 需求:
 1、启动设置后,暂停3秒,打开短信应⽤
 2、打印当前默认应⽤包名启动名
"""
sleep(3)
# 启动短信
driver.start_activity("com.android.messaging",".ui.conversationlist.Conversati
onListActivity")
# 打印包名和启动名
print("当前所在应⽤包名:",driver.current_package)
print("当前所在应⽤启动名:",driver.current_activity)
driver.quit()

在这里插入图片描述

"""
 需求:
 1、判断百年奥莱是否安装,如果安装进⾏卸载,否则安装
 2、启动设置界⾯
 3、置于后台3秒钟
 4、关闭设置界⾯
 5、关闭app驱动
"""
# 判断百年奥莱是否安装
if driver.is_app_installed("com.yunmall.lc"):
 print("百年奥莱app已存在正在卸载...")
  # 卸载
 driver.remove_app("com.yunmall.lc")
 print("卸载百年奥莱app成功!")
else:
 print("百年奥莱不存在,正在安装...")
 # 安装
 driver.install_app("/Users/lgy/PycharmProjects/lgy/bj37-web01/day07-
appium01//bainianaolaitemai_115.apk")
 print("安装百年奥莱app成功!")
sleep(3)
# 启动设置界⾯
print("启动设置界⾯...")
driver.start_activity("com.android.settings",".Settings")
sleep(3)
print("设置应⽤置于后台3秒钟...")
# 置于后台3秒
driver.background_app(3)
print("关闭设置app...")
# 关闭设置
driver.close_app()
print("获取关闭后的app报名")
print("关闭设置app,后获取包名:",driver.current_package)
sleep(3)
print("退出driver驱动")
driver.quit()

元素定位

单个元素定位
在这里插入图片描述
在这里插入图片描述

print("使⽤id点击放⼤镜...")
# 使⽤id -> 点击放⼤镜
driver.find_element_by_id("com.android.settings:id/search").click()
sleep(1)
print("使⽤class输⼊搜索hello...")
# 使⽤class 输⼊hell
driver.find_element_by_class_name("android.widget.EditText").send_keys("hello"
)
sleep(1)
print("使⽤xpath点击返回...")
# 点击返回 xpath
driver.find_element_by_xpath("//*
[@class='android.widget.ImageButton']").click()
sleep(1)
print("使⽤name点击搜索...")
# 使⽤name定位
driver.find_element_by_accessibility_id("搜索设置").click()
sleep(3)
driver.quit()

定位⼀组元素
在这里插入图片描述

# 1、获取所有id为:android:id/title
els = driver.find_elements_by_id("android:id/title")
for el in els:
 print("元素id为com.android.settings:id/title的为本内容有:",el.text)
els = driver.find_elements_by_class_name("android.widget.TextView")
for el in els:
 print("元素class为android.widget.TextView的为本内容有:",el.text)
els = driver.find_elements_by_xpath("//*[contains(@text,'设')]")
for el in els:
 print("⽂本包含'设'内容有:",el.text)

元素操作

方法:
1、点击:元素.click()
2、输⼊:元素.send_keys()
3、清空:元素.clear()
在这里插入图片描述

# 输⼊中⽂ 参数
desired_caps["unicodeKeyboard"] = True
desired_caps["resetKeyboard"] = True
# 1、点击放⼤镜
driver.find_element_by_xpath("//*[@resourceid='com.android.settings:id/search']").click()
# 2、输⼊hello
el = driver.find_element_by_xpath("//*[@resourceid='android:id/search_src_text']")
el.send_keys("hello")
# 3、2s 清空内容
sleep(2)
el.clear()
# 4、5s 输⼊你好
sleep(2)
el.send_keys("你好")

元素获取信息

⽅法
获取⽂本:元素.text
获取⼤⼩:元素.size
获取位置:元素.location

需求
1、打开设置app
2、点击放⼤镜
3、获取搜索⽂本值
4、计算搜索框中⼼触摸点

# 获取 菜单我的⽂本
text = driver.find_element_by_xpath("//*[@resourceid='android:id/search_src_text']").text
print("我的菜单,⽂本值为:",text)
location = driver.find_element_by_xpath("//*[@resourceid='android:id/search_src_text']").location
print("位置:",location)
size = driver.find_element_by_xpath("//*[@resourceid='android:id/search_src_text']").size
print("⼤⼩为:",size)
x= location.get("x")+ (size.get("width")/2)
y = location.get("y")+ (size.get("height")/2)
print("触摸中⼼位置x:{} y:{}".format(x,y))# 获取 菜单我的⽂本
text = driver.find_element_by_xpath("//*[@resourceid='android:id/search_src_text']").text
print("我的菜单,⽂本值为:",text)
location = driver.find_element_by_xpath("//*[@resourceid='android:id/search_src_text']").location
print("位置:",location)
size = driver.find_element_by_xpath("//*[@resourceid='android:id/search_src_text']").size
print("⼤⼩为:",size)
x= location.get("x")+ (size.get("width")/2)
y = location.get("y")+ (size.get("height")/2)
print("触摸中⼼位置x:{} y:{}".format(x,y))

获取元素属性

⽅法: 元素.get_attribute(“属性名”)
在这里插入图片描述
在这里插入图片描述

# 点击放⼤镜
els = driver.find_elements_by_id("com.android.settings:id/title")
for el in els:
 print("--"* 50)
 print("1、enabled属性值为:",el.get_attribute("enabled"))
 print("2、text属性值为:",el.get_attribute("text"))
 print("3、content-desc属性值为:",el.get_attribute("name"))
 print("4、resource-id属性值为:",el.get_attribute("resourceId"))
 print("5、class属性值为:",el.get_attribute("className"))
 print("--"* 50)

滑动

swipe(start_x,start_y,end_x,end_y)
特点:精准滑动(基于两个坐标 点滑动)
说明:针对坐标点进⾏操作

driver.swipe(100,1000,100,400,duration=2000)

scroll
特点:滚动(有惯性存在,滚动下不按下第⼀个元素)
说明:针对两个元素进⾏操作
drag_and_drop【推荐】
特点:拖拽(没有惯性,按下开始元素拖拽到指定元素位置)
说明:针对两个元素进⾏精准操作
在这里插入图片描述

手势操作

说明:
1、appium中封装了⼿势的操作⽅法,都在TouchAction类中,需要导包
2、所有的⼿势操作,最终都需要调⽤perform()⽅法才能执⾏

轻敲
api: TouchAction(driver).tap(el,x,y).perform()

from appium.webdriver.common.touch_action import TouchAction
wlan = driver.find_element_by_xpath("//*[@text='WLAN']")
TouchAction(driver).tap(wlan).perform()

按下与释放
按下: press(el,x,y)
释放: release()
示例

# 获取WLAN元素
wlan = driver.find_element_by_xpath("//*[@text='WLAN']")
loc = wlan.location
print(loc)
# 效果类似点击
TouchAction(driver).press(x=loc.get("x"),y=loc.get("y")).release().perform()

⻓按
⽅法: long_press(el,x,y)
场景: 在移动应⽤中,有时候需要⻓安才能激活菜单选项
示例:

# 获取WLAN元素
wlan = driver.find_element_by_xpath("//*[@text='WLAN']")
wlan.click()
# 必须暂时⼀定时间 暂停3秒(原因:元素未加载出来,直接⻓按坐标没有任何效果)
sleep(3)
# 效果类似点击
TouchAction(driver).long_press(x=777,y=375).perform()

移动及等待
移动:move_to(el,x,y)
等待: wait()
案例:九宫格解锁

"""
 需求:绘制解锁图案 Z
 绘制坐标点:
 1、1048,340 1377,340 1707,340
 2、1377,669
 3、1048,999 1377,999 1707,999
"""
# 1、定位WLAN
WLAN = driver.find_element_by_xpath("//*[@text='WLAN']")
# 2、定位应⽤
app = driver.find_element_by_xpath("//*[@text='应⽤']")
driver.drag_and_drop(app,WLAN)
# 3、点击安全
driver.find_element_by_xpath("//*[@text='安全']").click()
# 4、点击屏幕锁定⽅式
driver.find_element_by_xpath("//*[@text='屏幕锁定⽅式']").click()
# 5、点击图案
driver.find_element_by_xpath("//*[@text='图案']").click()
# 必须暂停,登录绘制⻚⾯加载完成
sleep(2)
# 6、绘制
TouchAction(driver).press(x=1048,y=340).wait(100).move_to(x=1377,y=340).wai
t(100).move_to(x=1707,y=340).wait(100)\
 
.move_to(x=1377,y=669).wait(100).move_to(x=1048,y=999).wait(100).move_to(x=
1377,y=999).wait(100).move_to(x=1707,y=999).wait(100)\
 .perform()

手机操作api

说明:使⽤appium框架的api操作android
常⽤api
查看当前⽹络类型
设置⽹络类型
查看当前分辨率
截图
扩展⽹络类型

在这里插入图片描述

# 1、查看当前⽹络类型
print("当前⽹络类型为:",driver.network_connection)
# 2、设置⽹络类型为⻜⾏模式
driver.set_network_connection(1)
print("设置之后的⽹络类型为:",driver.network_connection)
# 3、获取当前屏幕分辨率
print("当前屏幕分辨率为:",driver.get_window_size())
# 4、截图保存
driver.get_screenshot_as_file("./screen.png")

按键操作
在这里插入图片描述

"""
 需求:
 1、点击三次⾳量+ 24
 2、点击返回 4
 3、点击两次⾳量- 25
 """
i = 0
# 三次增⼤⾳量
while i < 3:
 driver.press_keycode(24)
 i += 1
sleep(2)
# 点击返回
driver.press_keycode(4)
i = 0
# 两次减⼩⾳量
while i < 2:
 driver.press_keycode(25)
 i += 1
 
# 提示:部分模拟器没有按键操作效果

通知栏
应⽤场景:检查服务器发送的通知

"""
 需求:
 1、打开通知栏,点击通知栏的信息
"""
# 打开通知栏
driver.open_notifications()
sleep(2)
# 查找信息并点击
driver.find_element_by_xpath("//*[@text='应⽤宝.apk']").click()

** 获取toast消息**
说明: toast消息为移动应⽤中,⼀种⿊底⽩字提示信息,有时间限制
为什么要获取toast消息?
断⾔内容
如何获取?
步骤
安装依赖库
配置driver启⽤参数
编写代码获取⽂本值
安装依赖库: lpip install uiautomator2
配置driver启⽤参数

desired_caps[‘automationName’] = ‘Uiautomator2’

编写代码获取⽂本值

# 获取toast消息
msg = driver.find_element_by_xpath("//*[contains(@text,'请先勾选同
意')]").text
print("toast消息为:",msg)

切换webview【了解】
app中嵌套web信息,如果不切换⽆法定位操作
如何切换
1、获取当前环境 --> driver.contexts
2、调⽤切换⽅法 --> driver.switch_to.context(“环境”)

# 获取当前所有的环境
print(driver.contexts)
# 切换环境
driver.switch_to.context("WEBVIEW_com.android.browser")

monkey
android系统⾃带⼀种测试压⼒的⼩⼯具,主要测试系统或应⽤稳定性
测试是否崩溃、闪退、死机

adb shell monkey -p com.yunmall.lc -v -v 10000 >xxx.log
-p:包名
-v -v:⽇志
10000:乱抓的时间次数
-s:设置随机种⼦数(两次执⾏随机种⼦数⼀样,执⾏的事件也是⼀样)
其他参数

在这里插入图片描述
搜索:“ANR”、ERROR、null、相关错误
在这里插入图片描述

练习案例

(appium+selenium+po封装)
实现的目标:1、app下单 2、web后台端进行发货
tpshop下单业务自动化业务实现(app)
实现效果
在这里插入图片描述
项目实施
要实现的业务:app下单流程
实现技术:python+appium+selenium
结构实现:po+日志+数据驱动+报告
执行方式:持续集成

结构搭建
在这里插入图片描述

import os
import time
from selenium.webdriver.support.wait import WebDriverWait
from config import DIR_PATH
class Base:
# 初始化方法
def __init__(self, driver):
self.driver = driver
# 查找元素方法
def base_find(self, loc, timeout=10, poll=0.5):
return WebDriverWait(self.driver, timeout, poll).until(lambda x:
x.find_element(*loc))
# 点击方法
def base_click(self, loc):
self.base_find(loc).click()
# 输入方法
def base_input(self, loc, value):
# 获取元素
el = self.base_find(loc)
# 清空
el.clear()
# 输入
el.send_keys(value)
# 获取文本方法
def base_get_text(self, loc):
return self.base_find(loc).text
# 截图方法
def base_get_img(self):
img_path = DIR_PATH + os.sep + "img" + os.sep + "
{}.png".format(time.strftime("%Y%m%d%H%M%S"))
self.driver.get_screenshot_as_file(img_path)

app登录page结构

class PageAppLogin:
# 1、点击 我的
def page_app_click_me(self):
pass
# 2、点击 登录头像
def page_app_click_login_link(self):
pass
# 3、输入用户名
def page_app_input_username(self):
pass
# 4、输入密码
def page_app_input_pwd(self):
pass
# 5、点击勾选协议
def page_app_click_pro(self):
pass
# 6、点击登录按钮
def page_app_click_login_btn(self):
pass
# 7、获取登录昵称
def page_app_get_nickname(self):
pass
# 8、组合业务方法
def page_app_login(self):
pass
"""
一、以下为app登录模块配置信息
"""
# 我的
app_login_me = By.XPATH, "//*[@text='我的']"
# 登录图片(连接)
app_login_link = By.XPATH, "//*[@resource-id='com.tpshop.malls:id/head_img']"
# 用户名
app_username = By.XPATH, "//*[@resource-id='com.tpshop.malls:id/mobile_et']"
# 密码
app_pwd = By.XPATH, "//*[@resource-id='com.tpshop.malls:id/pwd_et']"
# 协议
app_pro = By.XPATH, "//*[@resource-id='com.tpshop.malls:id/agree_btn']"
# 登录按钮
app_login_btn = By.XPATH, "//*[@resource-id='com.tpshop.malls:id/login_tv']"
# 昵称
app_nickname = By.XPATH, "//*[@resource-id='com.tpshop.malls:id/nick_name_tv']"

** 登录script实现**

import unittest
from page.page_app_login import PageAppLogin
from util import GetDriver
class TestAppLoginOrder(unittest.TestCase):
def setUp(self) -> None:
self.driver = GetDriver.get_app_driver()
# 获取PageAppLogin实例
self.app = PageAppLogin(self.driver)
def tearDown(self) -> None:
self.driver.quit()
def test01_login_order(self):
# 调用登录
self.app.page_app_login()
# 打印昵称->断言
nickname = self.app.page_app_get_nickname()
print("登录账户昵称为:", nickname)
# 提示:获取昵称需要加个强制等待时间 2

订单业务结构搭建(page_order.py)

class PageAppOrder:
# 点击首页
def page_app_click_index(self):
pass
# 点击搜索框
def page_app_click_search_text(self):
pass
# 输入搜索内容
def page_app_input_search_text(self):
pass
# 点击搜索按钮
def page_app_click_search_btn(self):
pass
# 选择商品
def page_app_select_photo(self):
pass
# 点击加入购物车
def page_app_add_cart(self):
pass
# 点击确定
def page_app_cart_ok(self):
pass
# 点击购物车
def page_app_click_cart(self):
pass
# 点击立即购买
def page_app_now_purchase(self):
pass
# 点击提交订单
def page_app_click_submit_order(self):
pass
# 点击 立即支付
def page_app_click_now_pay(self):
pass
# 输入 密码
def page_app_input_pwd(self):
pass
# 点击确定
def page_app_click_sure(self):
pass
# 获取订单编号
def page_app_get_order_on(self):
pass
# 下单业务方法
def page_app_order(self):
pass

在这里插入图片描述
web后台实现发货业务(今日实现)
持续集成->日志->报告->数据驱动
Base类
说明:由于web发货页面需要切换iframe标签,所以在Base类中新增两个方法(1、切换frame
2、回到默认目录)

# 切换frame
def base_switch_frame(self, loc):
# 获取元素
el = self.base_find(loc)
# 执行切换
self.driver.switch_to.frame(el)
# 恢复frame
def base_default_frame(self):
self.driver.switch_to.default_content()

Page类
结构搭建(page_web_login.py)

class PageWebLogin:
# 1、输入用户名
def page_web_username(self):
pass
# 2、输入密码
def page_web_pwd(self):
pass
# 3、输入验证码
def page_web_verify_code(self):
pass
# 4、点击登录按钮
def page_web_login_btn(self):
pass
# 5、获取登录昵称
def page_web_nickname(self):
pass
# 登录业务方法
def page_web_login(self):
pass

"""
三、web后台登录配置信息整理
"""
# 用户名
web_login_username = By.CSS_SELECTOR, "[name='username']"
# 密码
web_login_pwd = By.CSS_SELECTOR, "[name='password']"
# 验证码
web_login_verify = By.CSS_SELECTOR, "[name='vertify']"
# 登录按钮
web_login_submit = By.CSS_SELECTOR, "[name='submit']"
# 昵称
web_login_nickname = By.CSS_SELECTOR, ".bgdopa-t"

driver封装

# 获取Web Driver
@classmethod
def get_web_driver(cls):
if cls.__web_driver is None:
cls.driver = webdriver.Chrome()
cls.driver.get(HOST)
cls.driver.maximize_window()
return cls.driver

发货Page页面实现

import page, time
from base.base import Base
class PageWebOrder(Base):
# 订单菜单
def page_web_order_menu(self):
self.base_click(page.web_order)
# 左侧 发货单
def page_web_order_goods(self):
self.base_click(page.web_order_goods)
# 工作区域 去发货
def page_web_go_goods(self):
# 切换iframe
self.base_switch_frame(page.web_order_iframe)
self.base_click(page.web_order_go_goods)
# 物流公司
def page_order_company(self):
self.base_click(page.web_order_company)
# 配送单号
def page_order_input_order_no(self):
value = str(time.strftime("%Y%m%d%H%M%S"))
self.base_input(page.web_order_order_no, value)

# 确认发货
def page_order_goods_ok(self):
self.base_click(page.web_order_goods_ok)
# 打印配置单
def page_order_print_order(self):
self.base_click(page.web_order_print_order)
# 获取订单编号
def page_order_get_on(self):
return self.base_get_text(page.web_order_on)
# 订单发货业务
def page_order_go_goods(self):
self.page_web_order_menu()
self.page_web_order_goods()
self.page_web_go_goods()
self.page_order_company()
self.page_order_input_order_no()
self.page_order_goods_ok()
self.page_order_print_order()

Script类
test02_web_login_order.py
登录

import unittest
from time import sleep
from page.page_web_login import PageWebLogin
from util import GetDriver
class TestWebLoginOrder(unittest.TestCase):
def setUp(self) -> None:
self.driver = GetDriver.get_web_driver()
self.login = PageWebLogin(self.driver)
def tearDown(self) -> None:
sleep(1)
self.driver.quit()
def test01_web_login_order(self):
self.login.page_web_login()
nickname = self.login.page_web_nickname()
print("登录后的昵称为:",nickname)

订单配置信息整理

# 订单菜单
web_order = By.XPATH, "//a[text()='订单']"
# 左侧菜单 发货单
web_order_goods = By.XPATH, "//a[text()='发货单']"
# iframe
web_order_iframe = By.CSS_SELECTOR, "#workspace"
# 去发货 //div[text()='202112161517008312']/../..//td[@class='handle']//a[1]
web_order_go_goods = By.XPATH, "//a[text()='去发货']"
# 物流公司
web_order_company = By.CSS_SELECTOR, "[value='YZPY']"
# 配送单号
web_order_order_no = By.CSS_SELECTOR, "#invoice_no"
# 确认发货
web_order_goods_ok = By.CSS_SELECTOR, "ncap-btn-send"
# 打印配置单
web_order_print_order = By.CSS_SELECTOR, ".fa-print"
# 获取订单编号
web_order_on = By.XPATH, "//div[@id='printDiv']/div[@class='contactinfo']/dl[1]/dd[2]"
# 难点:如何根据指定单号,查找对应的去发货元素?
# 思路:想找共同的父级,在逐级查找

订单发货

import unittest
from time import sleep
import page
from page.page_web_login import PageWebLogin
from page.page_web_order import PageWebOrder
from util import GetDriver
class TestWebLoginOrder(unittest.TestCase):
def setUp(self) -> None:
self.driver = GetDriver.get_web_driver()
self.login = PageWebLogin(self.driver)
self.order = PageWebOrder(self.driver)
def tearDown(self) -> None:
sleep(1)
self.driver.quit()
def test01_web_login_order(self):
try:
# 登录
self.login.page_web_login()
nickname = self.login.page_web_nickname()
print("登录后的昵称为:", nickname)
# 发货
self.order.page_order_go_goods()
# 打印订单
order_no = self.order.page_order_get_on()
print("发货的订单为:", order_no)
# self.assertEqual(page.order_on,order_no)
except Exception as e:
print("错误原因:",e)
raise

日志封装

# 日志封装
class GetLog:
__log = None
@classmethod
def get_log(cls):
if cls.__log is None:
# 获取日志器
cls.__log = logging.getLogger()
# 设置入口级别
cls.__log.setLevel(logging.INFO)
# 获取处理器
filename = DIR_PATH + os.sep + "log" + os.sep +
"tpshop_auto.log"
tf =
logging.handlers.TimedRotatingFileHandler(filename=filename,
when="midnight",
interval=1,
backupCount=3,
encoding="utf-8")
# 获取格式器
fmt = "%(asctime)s %(levelname)s [%(filename)s(%(funcName)s:%
(lineno)d)] - %(message)s"
fm = logging.Formatter(fmt)
# 将格式器添加到处理器
tf.setFormatter(fm)
# 将处理器添加到日志器
cls.__log.addHandler(tf)
# 返回日志器
return cls.__log

#日志应用
1、记录程序运行步骤 base->info
2、记录程序错误 script->error

持续集成
报告无样式问题
System.setProperty(“hudson.model.DirectoryBrowserSupport.CSP”, “”)
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值