Web自动化测试

谷歌最新驱动下载

Chrome for Testing availability

安装selenium

pip install  selenium

selenium案例

import time

from selenium import webdriver

driver = webdriver.Chrome()
driver.get("https://www.baidu.com")

time.sleep(3)
driver.quit()

元素定位

为什么要学习元素定位方式?

1. 让程序操作指定元素,就必须先找到此元素;
2. 程序不像人类用眼睛直接定位到元素;
3. WebDriver提供了八种定位元素方式

WebDriver 元素定位方式 

1. id
2. name
3. class_name
4. tag_name
5. link_text
6. partial_link_text

定位方式分类-汇总:

1). id、name、class_name:为元素属性定位
2). tag_name:为元素标签名称
3). link_text、partial_link_text:为超链接定位(a标签)
4). Xpath:为元素路径定位
5). Css:为CSS选择器定位

案例1

1. 为了更好的学习这八种方式和网络的关系,我们在案例-1注册页面上来练习自动化脚本设计,提高学习效率和
   脚本执行速率
2. 语言使用Python
3. 开发工具使用Pycharm
4. selenium使用2.48.0

id定位

实现案例-1需求:
    1). 打开注册A.html页面,使用id定位,自动填写(账号A:admin、密码A:123456)
    2). 填写完毕后,3秒钟关闭浏览器窗口

实现

from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

input01 = driver.find_element(By.ID,"userA")
input01.send_keys("admin")
sleep(3)

input02 = driver.find_element(By.NAME,"passwordA")
input02.send_keys("123456")
sleep(3)

input03 = driver.find_element(By.CLASS_NAME,"telA")
input03.send_keys("123456")
sleep(3)

input04 = driver.find_element(By.TAG_NAME,"input")
input04.send_keys("123456")
sleep(3)

driver.quit()
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

# link = driver.find_element(By.LINK_TEXT,"访问 百度 网站")  搜索超链接内容等于访问 百度 网站
link = driver.find_element(By.PARTIAL_LINK_TEXT,"AA")   # 搜索超链接内容包含AA
link.click()
sleep(3)



driver.quit()
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)


input = driver.find_elements(By.TAG_NAME,"input")
#找出一堆输入框定位到第四个写入值

input[3].send_keys("121231312")


sleep(3)



driver.quit()

xpath、css定位

xpath安装

XPath Helper_2.0.2_Chrome插件下载_极简插件

使用xpath查询id等于userA元素
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)


input = driver.find_element(By.XPATH,"//input[@id='userA']")

input.send_keys("121231312")


sleep(3)



driver.quit()

xpath定位策略

1. 路径-定位
    1). 绝对路径
    2). 相对路径 
2. 利用元素属性-定位
3. 层级与属性结合-定位
4. 属性与逻辑结合-定位
定位方法 
driver.find_element(By.XPATH,"//input[@id='userA']")

路径(绝对路径、相对路径)

绝对路径:从最外层元素到指定元素之间所有经过元素层级路径 ;如:/html/body/div/p[2]
          提示:
          1. 绝对路径以/开始

相对路径:从第一个符合条件元素开始(一般配合属性来区分);如://input[@id='userA']
          提示:
          2. 相对路径以//开始

 案例-1

需求:
    1). 使用绝对路径和相对路径分别实现,账号A:admin;密码A:123456;自动化脚本设计
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

# 相对路径
input = driver.find_element(By.XPATH,"//input[@id='userA']")
input.send_keys("1231231")
sleep(3)

# 绝对路径
input02 = driver.find_element(By.XPATH,"/html/body/form/div/fieldset/p[2]/input");
input02.send_keys("121231312")
sleep(3)









driver.quit()
 利用元素属性
说明:快速定位元素,利用元素唯一属性;
示例://*[@id='userA']
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

# 利用元素id查找
input = driver.find_element(By.XPATH,"//input[@id='userA']")
input.send_keys("1231231")
sleep(3)











driver.quit()
层级与属性结合
说明:要找的元素没有属性,但是它的父级有;
示例://*[@id='p1']/input
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

#  层级与属性结合
input = driver.find_element(By.XPATH,"//*[@id='p1']/input")
input.send_keys("1231231")
sleep(3)











driver.quit()
属性与逻辑结合
说明:解决元素之间个相同属性重名问题
示例://*[@id='telA' and @class='telAa']
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

#  层级与属性结合
input = driver.find_element(By.XPATH,"//*[@id='telA' and  @class='telA' ]")
input.send_keys("1231231")
sleep(3)











driver.quit()
Xpath-延伸
//*[text()="xxx"]                            文本内容是xxx的元素

//*[starts-with(@attribute,'xxx')]                属性以xxx开头的元素

//*[contains(@attribute,'Sxxx')]                属性中含有xxx的元素

CSS定位

 什么是css
CSS 中选择器是一种模式,用于选择需要添加样式的元素。计算机能够通过CSS选择器定位到相应元素,我们在编写自动化测试脚本时是在不断地找到CSS选择器对应的元素。
CSS中通过各种选择器选择不同的页面元素,完成了颜色、字体、宽高等的设定,既然可以通过CSS选择器完成元素选择及样式设定,则也可利用CSS选择器的规则完成自动化测试脚本中的元素定位。
1. CSS(Cascading Style Sheets)是一种语言,它用来描述HTML和XML的元素显示样式;
2. 在CSS语言中有CSS选择器(不同的策略选择元素),在Selenium中也可以使用这种选择器;
提示:
    1. 在selenium中极力推荐CSS定位,因为它比XPath定位速度要快
    2. css选择器语法非常强大,在这里我们只学习在测试中常用的几个
 CSS定位常用策略 (方式)
1. id选择器
2. class选择器
3. 元素选择器
4. 属性选择器
5. 层级选择器
css选择器语法

基础选择器

 备注:某些元素属性有多个值(如class属性),值表现为以空格隔开,使用时需要单个取出使用

取telA或者haha 

组合选择器

组合选择器就是同时使用多个基础选择器,从而更好地筛选出目标元素

伪属性选择器

伪属性选择器是指元素在html中实际并不存在该属性,是由css定义的拓展描述属性

ID选择器
说明:根据元素id属性来选择
格式:#id      如:#userA    <选择id属性值为userA的所有元素>
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

#  层级与属性结合
input = driver.find_element(By.CSS_SELECTOR,'#userA')
input.send_keys("1231231")
sleep(3)





driver.quit()
class 选择器
说明:根据元素class属性来选择
格式:.class 如:.telA <选择class属性值为telA的所有元素>
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

#  层级与属性结合
input = driver.find_element(By.CSS_SELECTOR,'.telA')
input.send_keys("1231231")
sleep(3)





driver.quit()
元素选择器
说明:根据元素的标签名选择
格式:element 如:input <选择所有input元素>
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

#  层级与属性结合
input = driver.find_elements(By.CSS_SELECTOR,'input')
input[0].send_keys("1231231")
sleep(3)





driver.quit()
属性选择器
说明:根据元素的属性名和值来选择
格式:[attribute=value] 如:[type="password"] <选择所有type属性值为password的值>

补充:

  1. input[type^='p'] 说明:type属性以p字母开头的元素
  2. input[type$='d'] 说明:type属性以d字母结束的元素
  3. input[type*='w'] 说明:type属性包含w字母的元素
  4. input[type~='value'] 说明: type属性包含value的元素
  5. input[type=value] 说明: type属性是value的所有元素
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

#  层级与属性结合
input = driver.find_element(By.CSS_SELECTOR,'[name="userA"]')
input.send_keys("1231231")
sleep(3)





driver.quit()
层级选择器
说明:根据元素的父子关系来选择
格式:element>element 如:p>input <返回所有p元素下所有的input元素>
提示:> 可以用空格代替 如:p input 或者 p [type='password']
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By


driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

#  层级与属性结合
input = driver.find_element(By.CSS_SELECTOR,'p input')
input.send_keys("1231231")
sleep(3)





driver.quit()

 元素和浏览器操作方法

元素常用操作方法

1. clear()            清除文本
2. send_keys()        模拟输入
3. click()            单击元素

说明:由于这三个方法非常简单,并且有些之前已经使用过,所以在这里用一个案例一起来讲解

案例-1 用户注册A

需求:
    1. 通过脚本执行输入 用户名:admin;密码:123456;电话号码:18611111111;电子邮件:123@qq.com;
    2. 间隔3秒后,修改电话号码为:18600000000
    3. 间隔3秒,点击注册用户A
    4. 间隔3秒,关闭浏览器
    5. 元素定位方法不限
from selenium import webdriver

from time import sleep

from selenium.webdriver.common.by import By

driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

#  层级与属性结合
input01 = driver.find_element(By.ID, 'userA')
input01.send_keys("admin")
sleep(3)

input02 = driver.find_element(By.ID, 'passwordA')
input02.send_keys("123456")
sleep(3)

input03 = driver.find_element(By.ID, 'telA')
input03.send_keys("18611111111")
sleep(3)

input04 = driver.find_element(By.ID, 'emailA')
input04.send_keys("123@qq.com")
sleep(3)

input03.clear()
sleep(3)

input03.send_keys("186000000000")
sleep(3)

button = driver.find_element(By.CSS_SELECTOR, '[type="submitA"]')
button.click()

sleep(100)

driver.quit()

浏览器常用方法

WebDriver操作浏览器常用方法

1. maximize_window()                最大化 --> 模拟浏览器最大化按钮
2. set_window_size(100,100)            浏览器大小 --> 设置浏览器宽、高(像素点)
3. set_window_position(300,200)     浏览器位置 --> 设置浏览器位置
4. back()                             后退 --> 模拟浏览器后退按钮
5. forward()                         前进 --> 模拟浏览器前进按钮
6. refresh()                         刷新 --> 模拟浏览器F5刷新
7. close()                            关闭 --> 模拟浏览器关闭按钮(关闭单个窗口)
8. quit()                            关闭 --> 关闭所有WebDriver启动的窗口

WebDriver 操作浏览器方式-总结

# 最大化浏览器
driver.maximize_window()
# 刷新
driver.refresh()
# 后退
driver.back()
# 前进
driver.forward()
# 设置浏览器大小
driver.set_window_size(300,300)
# 设置浏览器位置
driver.set_window_position(300,200)
# 关闭浏览器单个窗口
driver.close()
# 关闭浏览器所有窗口
driver.quit()

 WebDriver 其他常用的方法

为什么要学习WebDriver其他方法?

1. 如何获取元素大小?
2. 如果获取元素的文本?
3. 如何获取元素属性值?
4. 如果让程序判断元素是否为可见状态?

我们想解决以上问题,就需要学习WebDriver封装其他操纵元素的方法

WebDriver其他常用方法

1. size                 返回元素大小
2. text                 获取元素的文本
3. title                 获取页面title
4. current_url            获取当前页面URL
5. get_attribute()         获取属性值
6. is_display()            判断元素是否可见
7. is_enabled()            判断元素是否可用
from selenium import webdriver



from selenium.webdriver.common.by import By

driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

size=driver.find_element(By.ID,"userA").size
print('size:',size)
# 获取a标签内容
text=driver.find_element(By.ID,"fwA").text
print('a标签text:',text)
# 获取title
title=driver.title
print('title:',title)
# 获取当前页面url
url=driver.current_url
print('url:',url)
# 获取a标签href属性值
href=driver.find_element(By.ID,"fwA").get_attribute("href")
print('href属性值为:',href)
# 判断span是否显示
display=driver.find_element(By.CSS_SELECTOR,'span').is_displayed()
print('span标签是否显示:',display)
# 判断取消按钮是否可用
enabled=driver.find_element(By.ID,'cancelA').is_enabled()
print('取消按钮是否可用:',enabled)



driver.quit()

设置元素等待

什么是元素等待?

概念:WebDriver定位页面元素时如果未找到,会在指定时间内一直等待的过程;

为什么要设置元素等待?

1. 由于网络速度原因
2. 电脑配置原因
3. 服务器处理请求原因

WebDriver元素等待有几种类型呢?

元素等待类型

1. 显式等待
2. 隐式等待
隐式等待:implicitly_wait() 
driver.implicitly_wait(10) #隐式等待10秒

由webdriver提供的方法,一旦设置,这个隐式等待会在WebDriver对象实例的整个生命周期起作用,它不针对某一个元素,是全局元素等待,即在定位元素时,需要等待页面全部元素加载完成,才会执行下一个语句。如果超出了设置时间的则抛出异常。 缺点:当页面某些js无法加载,但是想找的元素已经出来了,它还是会继续等待,直到页面加载完成(浏览器标签左上角圈圈不再转),才会执行下一句。某些情况下会影响脚本执行速度。

显示等待:WebDriverWait()
from selenium.webdriver.support.ui import WebDriverWait
WebDriverWait(self.driver, 5) # 等待5秒

具体样式:

WebDriverWait(driver,timeout,poll_frequency=0.5,ignored_exceptions=None)
  • driver:浏览器驱动

  • timeout:最长超时时间,默认以秒为单位

  • poll_frequency:检测的间隔步长,默认为0.5s

  • ignored_exceptions:超时后的抛出的异常信息,默认抛出NoSuchElementExeception异常。

通常会与until()或者until_not()方法结合使用:

WebDriverWait(driver,10).until(method,message="")
调用该方法提供的驱动程序作为参数,直到返回值为True
WebDriverWait(driver,10).until_not(method,message="")
调用该方法提供的驱动程序作为参数,直到返回值为False

在设置时间(10s)内,等待后面的条件发生。如果超过设置时间未发生,则抛出异常。在等待期间,每隔一定时间(默认0.5秒),调用until或until_not里的方法,直到它返回True或False.

WebDriverWait与expected_conditions结合使用
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
​
wait = WebDriverWait(driver,10,0.5)
element =waite.until(EC.presence_of_element_located((By.ID,"kw")),message="")
# 此处注意,如果省略message=“”,则By.ID外面是两层()

expected_conditions类提供的预期条件判断的方法:

方法说明
title_is判断当前页面的 title 是否完全等于(==)预期字符串,返回布尔值
title_contains判断当前页面的 title 是否包含预期字符串,返回布尔值
presence_of_element_located判断某个元素是否被加到了 dom 树里,并不代表该元素一定可见
visibility_of_element_located判断元素是否可见(可见代表元素非隐藏,并且元素宽和高都不等于 0)
visibility_of同上一方法,只是上一方法参数为locator,这个方法参数是 定位后的元素
presence_of_all_elements_located判断是否至少有 1 个元素存在于 dom 树中。举例:如果页面上有 n 个元素的 class 都是’wp’,那么只要有 1 个元素存在,这个方法就返回 True
text_to_be_present_in_element判断某个元素中的 text 是否 包含 了预期的字符串
text_to_be_present_in_element_value判断某个元素中的 value 属性是否包含 了预期的字符串
frame_to_be_available_and_switch_to_it判断该 frame 是否可以 switch进去,如果可以的话,返回 True 并且 switch 进去,否则返回 False
invisibility_of_element_located判断某个元素中是否不存在于dom树或不可见
element_to_be_clickable判断某个元素中是否可见并且可点击
staleness_of等某个元素从 dom 树中移除,注意,这个方法也是返回 True或 False
element_to_be_selected判断某个元素是否被选中了,一般用在下拉列表
element_selection_state_to_be判断某个元素的选中状态是否符合预期
element_located_selection_state_to_be跟上面的方法作用一样,只是上面的方法传入定位到的 element,而这个方法传入 locator
alert_is_present判断页面上是否存在 alert

场景运用

实际使用的情况:

waite = WebDriverWait(self.driver, 5)
element = waite.until(EC.title_is("XX首页"), '页面标题显示异常!') # 如果页面的标题显示不是“XX首页”,则会抛出异常“页面标题显示异常”
waite = WebDriverWait(self.driver, 4)
ele = waite.until(EC.presence_of_element_located((By.CSS_SELECTOR, '#厂家\$Menu > li:nth-child(4)')), '未找到对应元素')
ele.click()

也可以这样:

WebDriverWait(self.driver, 1).until(EC.presence_of_element_located((By.ID, 'name')), '未找到姓名').send_keys(name)
WebDriverWait(self.driver, 1).until(EC.presence_of_element_located((By.ID, 'certNo')), '未找到身份证').send_keys(idcard)

显式等待【了解 】

概念:使WebDriver等待指定元素条件成立时继续执行,否则在达到最大时长时抛出超时异常(TimeoutException)

提示:
    1). 在WebDriver中把显式等待的相关方法封装在WebDriverWait类中
    2). 等待是判定条件成立时,那如何判断条件成立?相关判断的方法封装在expected_conditions类中

 案例-1 注册页面A

需求:
    1. 如果用户名文本框存在,就输入admin

实现难点分析

1. 导包 等待类         --> from selenium.webdriver.support.wait import WebDriverWait
2. 导包 判断条件     --> from selenium.webdriver.support import expected_conditions as EC
                        (将expected_conditions 通过as关键字起个别名:EC)
3. WebDriverWait(driver, timeout, poll_frequency=0.5)
        1). driver:浏览器对象
        2). timeout:超时的时长,单位:秒
        3). poll_frequency:检测间隔时间,默认为0.5秒
4. 调用方法 until(method):直到..时
        1). method:调用EC.presence_of_element_located(element)
                    element:调用By类方法进行定位

案例-1 代码示例

from time import sleep

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.wait import WebDriverWait

driver = webdriver.Chrome()

url = r"D:\注册A.html"
driver.get(url)

#结合使用WebDriverWait,ExpectedConditions完成,注意,经过我反复测试才发现,这个方法目的是检查某个元素的innerText是否在指定时间范围内出现,

element = WebDriverWait(driver, 5).until(EC.presence_of_element_located((By.ID, 'userA')))
element.send_keys("admin")


sleep(10)

driver.quit()

隐式等待【掌握】

说明:等待元素加载指定的时长,超出抛出NoSuchElementException异常,实际工作中,一般都使用隐式等待;

显式与隐式区别:
    1. 作用域:显式等待为单个元素有效,隐式为全局元素
    2. 方法:显式等待方法封装在WebDriverWait类中,而隐式等待则直接通过浏览器实例化对象调用

隐式等待调用方法

方法:implicitly_wait(timeout)
      (timeout:为等待最大时长,单位:秒)

调用:driver.implicitly_wait(10)
      (driver:为浏览器实例化对象名称)

隐式等待执行-说明

如果定位某一元素定位失败,那么就会触发隐式等待有效时长,如果在指定时长内加载完毕,则继续执行,否则
抛出NoSuchElementException异常,如果元素在第一次就定位到则不会触发隐式等待时长;

鼠标、键盘操作

鼠标事件

说明:WebDriver库对模拟鼠标操作封装的一些方法,此知识点作为了解

WebDriver为什么要操作鼠标? 

说明:现在Web产品中提供了丰富的鼠标交互方式,如:双击、悬停、拖拽等功能,做为Web产品测试框架,需要
      应对这些Web产品应用场景,所以在WebDriver类库中封装了相应的鼠标交互方法。

疑问: WebDriver提供了那些操作鼠标事件的方法?

WebDriver操作鼠标方法

说明:在WebDriver中将操作鼠标的方法封装在ActionChains类中

1. context_click()            右击 --> 此方法模拟鼠标右键点击效果
2. double_click()            双击 --> 此方法模拟双标双击效果
3. drag_and_drop()            拖动 --> 此方法模拟双标拖动效果
4. move_to_element()        悬停 --> 此方法模拟鼠标悬停效果
5. perform()                执行 --> 此方法用来执行以上所有鼠标方法

为了更好的学习其他方法,我们先学习perform()执行方法,因为所有的方法都需要执行才能生效

 鼠标执行-perform() 

说明:在ActionChains类中所有提供的鼠标事件方法,在调用的时候所有的行为都存储在ActionChains类中,
      而perform()方法就是执行所有ActionChains中的行为

提示:必须调用perform()方法才能执行鼠标事件

 鼠标右键-context_click()

说明:在ActionChains类中的鼠标右键方法是个已知的bug,因为它能点击右键出现菜单,但无法选择右键菜单选
      项,因此方法了解即可

需求:
    案例-1注册页面A,在用户名文本框上点击鼠标右键
import time
# 导包
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By


# 创建driver对象
driver = webdriver.Chrome()
action = ActionChains(driver)

# 浏览器窗口最大化
# driver.maximize_window()
# time.sleep(1)

url = r"D:\注册A.html"
# 打开指定的url
driver.get(url)
time.sleep(1)

userA = driver.find_element(By.ID,"userA")
userA.send_keys("admin")
# 右击
action.context_click(userA).perform()

time.sleep(2)
driver.quit()

代码实现关键点分析

1. 导包:from selenium.webdriver.common.action_chains import ActionChains
2. 实例化ActionChains对象:Action=ActionChains(driver)
3. 调用右键方法:element=Action.context_click(username)
4. 执行:element.perform()

鼠标双击-double_click()

说明:模拟双击鼠标左键操作

需求:
    案例-1注册页面A,给用户名设置为admin,暂停3秒钟后双击鼠标左键,选中admin;

代码实现关键点分析

1. 导包...
2. 实例化...
3. 调用双击方法:element=Action.double_click(username)
4. 执行...
import time
# 导包
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By


# 创建driver对象
driver = webdriver.Chrome()
action = ActionChains(driver)

# 浏览器窗口最大化
# driver.maximize_window()
# time.sleep(1)

url = r"D:\注册A.html"
# 打开指定的url
driver.get(url)
time.sleep(1)

userA = driver.find_element(By.ID,"userA")
userA.send_keys("admin")
# 右击
action.double_click(userA).perform()

time.sleep(2)
driver.quit()

鼠标拖动-drag_and_drop()

说明:模拟鼠标拖动动作,选定拖动源元素释放到目标元素

拖动关键点分析

1. 源元素   socure=driver.find_element(By.ID,xxx)
2. 目标元素 target=driver.find_element(By.ID,xxx)
3. 调用方法 Action.drag_and_drop(source,target).perform()
import time
# 导包
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By

# 创建driver对象
driver = webdriver.Chrome()
action = ActionChains(driver)

# 浏览器窗口最大化
# driver.maximize_window()
# time.sleep(1)

url = r"D:\注册A.html"
# 打开指定的url
driver.get(url)
time.sleep(1)

userA = driver.find_element(By.ID, "userA")

userB = driver.find_element(By.ID, "passwordA")

# 拖动
action.drag_and_drop(userA, userB).perform()

time.sleep(2)
driver.quit()

鼠标悬停-move_to_element()

说明: 模拟鼠标悬停在选中的元素

需求:
    案例-1注册页面A,将模拟鼠标悬停 用户注册A 按钮,显示加入会员A提示

代码实现关键点分析

1. 导包...
2. 实例化...
3. 调用悬停方法:Action.move_to_element(element).perform()

import time
# 导包
from selenium import webdriver
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.by import By

# 创建driver对象
driver = webdriver.Chrome()
action = ActionChains(driver)

# 浏览器窗口最大化
# driver.maximize_window()
# time.sleep(1)

url = r"D:\注册A.html"
# 打开指定的url
driver.get(url)
time.sleep(1)

userA = driver.find_element(By.CSS_SELECTOR, '[type="submitA"]')


# 悬停
action.move_to_element(userA).perform()

time.sleep(2)
driver.quit()

键盘操作

说明:
    1). 模拟键盘上一些按键或者组合键的输入 如:Ctrl+C 、Ctrl+V;
    2). WebDriver中对键盘的操作都封装在Keys类中

Keys类

导包:from selenium.webdriver.common.keys import Keys

 常用的键盘操作

1. send_keys(Keys.BACK_SPACE)删除键(BackSpace) 
2. send_keys(Keys.SPACE)空格键(Space) 
3. send_keys(Keys.TAB)制表键(Tab) 
4. send_keys(Keys.ESCAPE)回退键(Esc) 
5. send_keys(Keys.ENTER)回车键(Enter) 
6. send_keys(Keys.CONTROL,'a') 全选(Ctrl+A) 
7. send_keys(Keys.CONTROL,'c')复制(Ctrl+C)

提示:以上方法就不一个一个讲解了,因为调用方法都一样;

 案例-1 注册页面A

需求:
    1). 输入用户名:admin1,暂停2秒 删除1
    2). 全选用户名:admin      暂停2秒
    3). 复制用户名:admin      暂停2秒
    4). 粘贴到密码框          暂停2秒
    5). 关闭浏览器
import time
# 导包
from selenium import webdriver
from selenium.webdriver.common.keys import Keys

from selenium.webdriver.common.by import By

# 创建driver对象
driver = webdriver.Chrome()

url = r"D:\注册A.html"
# 打开指定的url
driver.get(url)
time.sleep(1)

# 获取两个元素
userA = driver.find_element(By.ID,"userA")
emailA = driver.find_element(By.ID,"emailA")

userA.send_keys('admin123')
time.sleep(1)
# 删除
userA.send_keys(Keys.BACK_SPACE)
time.sleep(1)
# 从第一个元素里全选 复制 ctrl+a ctrl+c
userA.send_keys(Keys.CONTROL, "a")
userA.send_keys(Keys.CONTROL, "c")
# 在第二个元素里粘贴 ctrl+v
emailA.send_keys(Keys.CONTROL, "v")


time.sleep(2)
driver.quit()

案例-1 方法示例

# 定位用户名
element=driver.find_element(By.ID,"userA")
# 输入用户名
element.send_keys("admin1")
# 删除1
element.send_keys(Keys.BACK_SPACE)
# 全选
element.send_keys(Keys.CONTROL,'a')
# 复制
element.send_keys(Keys.CONTROL,'c')
# 粘贴
driver.find_element(By.ID,'passwordA').send_keys(Keys.CONTROL,'v')

 下拉选择框、警告框、滚动条操作

什么是下拉选择框

说明:下拉框就是HTML中<select>元素;

 为什么学习下拉选择框?

需求:
案例-1 注册页面A,城市选项-暂停2秒后选择上海A,暂停2秒后选择重庆,暂停2秒后选择广州

 案例-1 实现方式

1. 定位option选项
2. 定位方式不限

 Select类

说明:Select类是WebDriver为解决select标签定位诞生的,此类定位的是select标签

select类有哪些方法?

 select方法:

1. select_by_index()                --> 根据option索引来定位,从0开始
2. select_by_value()                --> 根据option属性 value值来定位
3. select_by_visible_text()            --> 根据option显示文本来定位

 Select类实现 步骤分析:

1. 导包 Select类 --> from selenium.webdriver.support.select import Select
2. 实例化Select类 select=Select(WebElemet)
                    (WebElement):driver.find_element(By.ID,"selectA"))
3. 调用方法:select.select_by_index(index)
                (index:为列表索引,从0开始)

 Select实现代码 总结

实现方式一:


import time
# 导包
from selenium import webdriver

from selenium.webdriver.common.by import By
# 创建driver对象
from selenium.webdriver.support.select import Select

driver = webdriver.Chrome()

url = r"D:\注册A.html"
# 打开指定的url
driver.get(url)
time.sleep(1)

# 常见select对象
select = Select(driver.find_element(By.ID,"selectA"))

# # 通过索引选择 索引从0开始
# select.select_by_index(1)
# time.sleep(2)
#
# # 通过属性value的值选择
# select.select_by_value("gz")
# time.sleep(2)
#
# # 通过html显示内容选择
# select.select_by_visible_text("A重庆")

# print(select.options)
# print(len(select.options))

# 所有option标签对象都存在select.options里, 是个列表
for option in select.options:
    option.click()
    time.sleep(2)

time.sleep(2)
driver.quit()

实现方式二:

#导包
from selenium.webdriver.support.select import Select
...
# 1. 根据索引实现
select.select_by_index(1)
select.select_by_index(3)
select.select_by_index(2)
# 2. 根据文本值实现
select.select_by_visible_text("A上海")
select.select_by_visible_text("A重庆")
select.select_by_visible_text("A广州")
# 3. 根据value属性实现
select.select_by_value("sh")
select.select_by_value("cq")
select.select_by_value("gz")
...

警告框

需求

对案例-1 注册页面A,首先点击alerta按钮,其次输入用户名:admin

问题

1. 按钮被点击后弹出对话框,而接下来输入用户名的语句没有生效

警告框处理

说明:WebDriver中对处理警告框的操作,有专用的处理方法;

提示:
    HTML中常用的对话框有三种,处理的方法都一样
        1). alert
        2). confirm
        3). prompt

警告框处理方法

1. text                 --> 返回alert/confirm/prompt中的文字信息
2. accept()                --> 接受对话框选项
3. dismiss()            --> 取消对话框选项

调用方法

1. 获取警告框 
        alert=driver.switch_to.alert
2. 调用
        alert.text
        alert.accept()
        alert.dismiss()

 处理警告框-总结

...
# 定位alerta按钮
driver.find_element(By.ID,"alerta").click()
# 获取警告框
alert=driver.switch_to.alert
# 打印警告框文本
print(alert.text)
# 接受警告框
alert.accept()
# 取消警告框
#alert.dismiss()
...
from selenium.webdriver.common.by import By

import time
# 导包
from selenium import webdriver

driver = webdriver.Chrome()

url = r"D:\css_example.html"
# 打开指定的url
driver.get(url)
time.sleep(1)

# 获取元素并点击
driver.find_element(By.XPATH, "/html/body/input[1]").click()
# 切换到alter弹框
alter = driver.switch_to.alert
time.sleep(1)
# 进行操作
alter.accept()

# 获取元素并点击
driver.find_element(By.XPATH, "/html/body/input[2]").click()
# 切换到alter弹框
alter = driver.switch_to.alert
time.sleep(1)
# 进行取消操作
print(alter.text)
alter.dismiss()

# 获取元素并点击
driver.find_element(By.XPATH, "/html/body/input[3]").click()
# 切换到alter弹框
alter = driver.switch_to.alert
time.sleep(1)
# alter.send_keys("哈哈")
time.sleep(2)
# 进行操作
alter.dismiss()

time.sleep(2)
driver.quit()

滚动条

滚动条操作

说明:WebDriver类库中并没有直接提供对滚动条进行操作方法,但是它提供了可调用JavaScript脚本的方法,所
      以我们可以通过JavaScript脚本来达到操作滚动条的目的;

备注:
    1). 滚动条:一种可控制程序显示范围的组件
    2). JavaScript:一种流行脚本语言,可以操作HTML标签;
            JavaScript学习资料:http://www.w3school.com.cn/js/js_intro.asp

为什么要学习滚动条操作?

1. 在HTML页面中,由于前端技术框架的原因,页面元素为动态显示,元素根据滚动条的下拉而被加载
2. 页面注册同意条款,需要滚动条到最底层,才能点击同意
需求
案例-1 注册页面A,打开页面2秒后,滚动条拉倒最底层
需求实现分析:
1. 设置JavaScritp脚本控制滚动条  js="window.scrollTo(0,1000)"
                                    (0:左边距;1000:上边距;单位像素)
2. WebDriver调用js脚本方法  driver.execute_script(js)

3.2 控制滚动条实现代码

...
# 最底层
js1="window.scrollTo(0,1000)"
# 最顶层
js2="window.scrollTo(0,0)"
# 执行最底层
driver.execute_script(js1)
# 执行最顶层
driver.execute_script(js2)
...
from selenium.webdriver.common.by import By

import time
# 导包
from selenium import webdriver

driver = webdriver.Chrome()
driver.set_window_size(500, 600)

url = r"D:\注册A.html"
# 打开指定的url
driver.get(url)
time.sleep(1)

# 向下滚动1000单位
script = "window.scrollTo(0,1000)"
driver.execute_script(script)
time.sleep(2)

# 向右滚动1000单位
script = "window.scrollTo(1000,1000)"
driver.execute_script(script)

time.sleep(2)
driver.quit()

3.3 滚动条总结

1. WebDriver控制滚动方法
2. JavaScript控制滚动条语句

备注:js控制滚动条语句有很多种,如:js=document.documentElement.scrollTop=1000;但是推荐使用JS调用
      window句柄去控制;

frame表单切换、多窗口切换

目标

1. 掌握WebDriver切换frame表单方法
2. 掌握WebDriver多窗口切换的技巧

frame表单

frame:HTML页面中的一种框架,主要作用是在当前页面中指定区域显示另一页面元素;
       (HTML语言中,frame/iframe标签为表单框架)

为什么要学习frame表单切换

需求:案例-2 注册实例.html
    1. 此页面有三个注册界面,先填写最上边注册信息,其次填写注册A页面注册信息,最后填写注册B页面信息
    2. 定位方式不限
问题
1. 当前页面内无法定位注册页面A和注册页面B

frame表单切换

说明:在WebDriver类库中封装了HTML页面中使用frame表单框架技术定位的方法

方法:
    1). driver.switch_to.frame("myframe1")        -->    切换表单方法
            (myframe1:为frame表单的name或id)
    2). driver.switch_to.default_content()        --> 恢复默认页面方法
            (在frame表单中操作其他页面,必须先回到默认页面,才能进一步操作)

frame表单切换

说明:在WebDriver类库中封装了HTML页面中使用frame表单框架技术定位的方法

方法:
    1). driver.switch_to.frame("myframe1")        -->    切换表单方法
            (myframe1:为frame表单的name或id)
    2). driver.switch_to.default_content()        --> 恢复默认页面方法
            (在frame表单中操作其他页面,必须先回到默认页面,才能进一步操作)

案例-2解决方案

1. 完成当前页面注册信息;
2. 调用表单切换方法(switch_to.frame("myframe1"))切换到注册用户A表单中
3. 调用恢复默认页面方法(switch_to.default_content())
4. 调用表单切换方法(switch_to.frame("myframe2"))切换到注册用户B表单中
from selenium.webdriver.common.by import By

import time
# 导入webdriver包
from selenium import webdriver

# 创建driver对象
driver = webdriver.Chrome()
# 最大化窗口
driver.maximize_window()
# 设置隐式等待时间
driver.implicitly_wait(30)
# 打开指定url
driver.get(r"D:\注册实例.html")
time.sleep(1)

# 跳转到指定frame表单
driver.switch_to.frame("myframe1")
driver.find_element(By.ID,"userA").send_keys("admin")
time.sleep(2)

# 跳转回默认页面
driver.switch_to.default_content()
# 跳转到父级页面
# driver.switch_to.parent_frame()

driver.switch_to.frame("myframe2")
driver.find_element(By.ID,"userB").send_keys("adminB")

time.sleep(3)
driver.quit()


表单切换-总结

1. HTML中常用的表单框架
2. 切换表单方法
3. 为什么要恢复默认页面?

4. 恢复默认页面方法
切到frame框架中之后,我们便不能继续操作主文档的元素,这时如果想操作主文档内容,则需切回主文档。
有了parent_frame()这个相当于后退的方法,我们可以随意切换不同的frame框架,随意的在不同的层级的frame框架中跳来跳去了。

多窗口

说明:在HTML页面中,经常有a标签也就是超链接,这些链接在被执行时,有的会在新的窗口打开链接;
from selenium.webdriver.common.by import By

import time
# 导入webdriver包
from selenium import webdriver

# 创建driver对象
driver = webdriver.Chrome()
# 最大化窗口
driver.maximize_window()
# 设置隐式等待时间
driver.implicitly_wait(30)
# 打开指定url
driver.get(r"D:\注册A.html")
time.sleep(1)

# 获取当前窗口句柄
print("当前页:", driver.current_window_handle)
# 获取全部窗口句柄
print("所有:", driver.window_handles)

driver.find_element(By.ID,"fwA").click()
print("关闭原页面前:", driver.window_handles)
time.sleep(6)

# 跳转到新的窗口
driver.switch_to.window(driver.window_handles[1])
print(driver.current_window_handle)
driver.find_element(By.ID,"kw").send_keys("python")

time.sleep(6)

# driver.close()
# print("关闭原页面后:", driver.window_handles)

# time.sleep(3)
# driver.quit()



为什么要切换窗口?

案例-2 注册实例.html
需求:
    1). 点击注册A页面链接,在打开的页面,填写A页面注册信息;
问题
1). 无法定位注册A页面

多窗口切换

说明:在WebDriver中封装了获取当前窗口句柄方法和获取所有窗口句柄的方法以及切换指定句柄窗口的方法;
      (句柄:英文handle,窗口的唯一识别码)

方法:
    1). driver.current_window_handle         --> 获取当前窗口句柄
    2). driver.window_handles                 --> 获取所有窗口句柄
    3). driver.switch_to.window(handle)        --> 切换指定句柄窗口

案例-2 解决方案分析

1. 获取注册实例.html当前窗口句柄
2. 点击注册实例.html页面中注册A页面
3. 获取所有窗口句柄
4. 遍历判断窗口句柄并切换到注册A页面
5. 操作注册A页面元素,注册信息
from selenium.webdriver.common.by import By


import time
# 导入webdriver包
from selenium import webdriver

# 创建driver对象
driver = webdriver.Chrome()
# 最大化窗口
driver.maximize_window()
# 设置隐式等待时间
driver.implicitly_wait(10)
# 打开指定url
driver.get(r"D:\注册实例.html")
time.sleep(1)

# 跳转到指定frame表单
driver.switch_to.frame("myframe1")
driver.find_element(By.ID,"fwA").click()
time.sleep(10)

print("打开新窗口后:", driver.window_handles)

# 跳转到新窗口
# 在浏览器当中,如果在页面进行了某个操作,结果浏览器打开了另外一个新窗口(tab)。
# 如果要操作新窗口当中的,页面元素,就需要窗口切换。
driver.switch_to.window(driver.window_handles[1])
time.sleep(10)

# 跳转回老窗口
driver.switch_to.window(driver.window_handles[0])

# 回到老窗口后, 焦点默认在住页面
driver.switch_to.frame("myframe1")
driver.find_element(By.ID,"userA").send_keys("admin")

time.sleep(3)
driver.quit()





多窗口切换-总结

1. 什么是句柄?
2. 获取当前窗口句柄方法
3. 获取所有窗口句柄方法
4. 切换指定句柄窗口方法

窗口截图

 截图

说明:把当前操作页面,截图保存到指定位置

为什么要窗口截图?

说明:自动化脚本是由程序去执行的,因此有时候打印的错误信息并不是十分明确。如果在执行出错的时候对当前
      窗口截图保存,那么通过图片就可以非常直观地看到出错的原因。

窗口截图

说明:在WebDriver类库中,提供了截图方法,我们只需要调用即可;

方法:
    1). get_screenshot_as_file(imgpath)            --> 截取当前窗口
        (imgpath:图片保存路径)

案例-2 注册实例.html

需求:
    1. 填写注册A页面注册信息,填写完毕,截图保存;
from selenium.webdriver.common.by import By

import time
# 导入webdriver包
from selenium import webdriver

# 创建driver对象
driver = webdriver.Chrome()
# 最大化窗口
driver.maximize_window()
# 设置隐式等待时间
driver.implicitly_wait(30)
# 打开指定url
driver.get(r"D:\注册A.html")
time.sleep(1)

driver.find_element(By.ID, "userA").send_keys("admin")
# 给图片命名
# img_name = time.strftime("%Y%m%d_%H%M%S")
img_name = str(time.time()).replace(".", "_")
# 截图并生成图片
driver.get_screenshot_as_file("D:\%s.png" % img_name)

time.sleep(3)
driver.quit()

案例2-解决方案步骤

1. 打开注册实例.html
2. 切换注册A页面frame表单         --> driver.switch_to.frame(myframe1)
3. 输入注册信息
4. 调用截屏方法                    --> driver.get_screenshot_as_file("../Image/Image01.jpg")

验证码处理

说明:一种随机生成的信息(图片、数字、字母、汉字、算术题)等为了防止恶意的请求行为,增加应用的安全性。

为什么要学习验证码?

说明:在Web应用中,大部分系统在用户登陆的时候都要求输入验证码,而我们在设计自动化脚本时候,就需要面
      临这验证码的问题。

验证码的处理方式

说明:WebDriver类库中没有对验证码处理的方法,但是在这里可以叙说下针对验证码的几种常用处理方式;

方式:
    1). 去掉验证码
            (测试环境下-采用)
    2). 设置万能验证码
            (生产环境-采用)
    3). 验证码识别技术
            (通过Python-tesseract来识别图片类型验证码;识别率很难达到100%)
    4). 记录cookie
            (通过记录cookie进行登录-推荐)
提示:
1. 去掉验证码、设置万能验证码:太简单都是开发来完成,我们在这里不做讲解
2. 验证码识别技术:成功率不高,验证码种类繁多,不太适合;
3. 记录cookie:比较实用,我们对它进行下讲解;

cookie是什么?

cookie:
    1. Cookie是一小段的文本信息;格式:python中的字典(键值对组成)
    2. Cookie产生:客户端请求服务器,如果服务器需要记录该用户状态,就向客户端浏览器颁发一个Cookie格式
    3. Cookie使用:当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器,服务器检
       查该Cookie,以此来辨认用户状态。

为什么记录cookie?

说明:
    1. 用户第一次登陆时,勾选下次直接登陆或者记住密码,就是采用记录cookie实现的
    2. cookie内记录用户名和密码(加密)信息,只要请求时服务器收到cookie,就识别成功,默认为已登陆。

3.3 记录cookie

说明:
    1. WebDriver中对cookie操作提供相应的方法

方法:
    1. get_cookie(name)                    --> 获取指定cookie
       (name:为健名)
    2. get_cookies()                    --> 获取本网站所有本地cookies
    3. add_cookie(str)                    -->    添加cookie
       (str:为python中的字典格式)
案例-3 访问百度
需求:
    1. 登陆百度,获取cookie
    2. 使用获取的cookie,在WebDriver中,添加Cookie,达到登陆目的
案例3-实现步骤分析
1. 登陆baidu,登陆的时候抓取 (BAIDUID,BDUSS)
2. 使用add_cookie()方法,添加 (BAIDUID,BDUSS)键和值
3. 调用刷新方法 driver.refresh()
代码示例
from selenium import webdriver
import time
driver=webdriver.Firefox()
driver.get("https://www.baidu.com")
driver.add_cookie({'name':'BAIDUID','value':'根据实际填写'})
driver.add_cookie({'name':'BDUSS','value':'根据实际填写'})
time.sleep(3)
driver.refresh()
time.sleep(3)

窗口截屏、验证码总结

1. 截屏方法
2. 验证码常用的处理方式
3. Cookie的作用

UnitTest框架

什么是UnitTest框架?

概念:UnitTest框架是专门用来进行执行代码测试的框架;

为什么使用UnitTest框架?

1. 能够组织多个用例去执行
2. 提供丰富的断言方法
3. 提供丰富的日志与测试结果

UnitTest核心要素

1. TestCase
2. TestSuite
3. TextTestRunner
4. Fixture

 TestCase

明:(翻译:测试用例)一个TestCase就是一条测试用例;
使用:
    1. 导包:import unittest             --> 导入unitest框架
    2. 继承:unittest.TestCase             --> 新建测试类继承unittest.TestCase

提示:
    1). 测试用例:在自动化测试中,一条用例就是一个完整的测试流程;                
    2). 测试方法名称命名必须以test开头;
       (原因:unittest.TestCase类批量运行的方法是搜索执行test开头的方法)
import unittest


def add(x, y):
    return x + y;


class TestCase01(unittest.TestCase):  # 新建测试类必须继承unittest.TestCase
    def testcase_01(self):
        print("testcase_01")
        print("1+1=", add(1, 1))

    def testcase_02(self):
        print("testcase_02")
        print("2+2=", add(2, 2))


if __name__ == '__main__':
    unittest.main()

 设置单独一个测试案例:

TestSuite

说明:(翻译:测试套件)多条测试用例集合在一起,就是一个TestSuite;
使用:
    1. 实例化:     suite=unittest.TestSuite()                    
                 (suite:为TestSuite实例化的名称)
    2. 添加用例:suite.addTest("ClassName(MethodName)")    
                 (ClassName:为类名;MethodName:为方法名)

    3. 添加扩展:suite.addTest(unittest.makeSuite(ClassName))
                 (搜索指定ClassName内test开头的方法并添加到测试套件中)

提示:
    1). 一条测试用例(.py)内,多个方法也可以使用测试套件
    2). TestSuite需要配合TextTestRunner才能被执行

TextTestRunner

说明:(翻译:测试执行)是用来执行测试用例套件
使用:
    1. 实例化: runner=unittest.TextTestRunner()
                (runner:TextTestRunner实例化名称)
    2. 执行:    runner.run(suite)
                (suite:为测试套件名称)

test.py

import unittest


def add(x, y):
    return x + y;


class TestCase01(unittest.TestCase):  # 新建测试类必须继承unittest.TestCase
    def testcase_01(self):
        print("testcase_01")
        print("1+1=", add(1, 1))

    def testcase_02(self):
        print("testcase_02")
        print("2+2=", add(2, 2))

    def testcase_03(self):
        print("testcase_03")
        print("2+2=", add(3, ))

class TestCase02(unittest.TestCase):  # 新建测试类必须继承unittest.TestCase
    def testcase_01(self):
        print("testcase_01")
        print("1+1=", add(1, 1))

    def testcase_02(self):
        print("testcase_02")
        print("2+2=", add(2, 2))

    def testcase_03(self):
        print("testcase_03")
        print("2+2=", add(3, ))
class TestCase03(unittest.TestCase):  # 新建测试类必须继承unittest.TestCase
    def testcase_01(self):
        print("testcase_01")
        print("1+1=", add(1, 1))

    def testcase_02(self):
        print("testcase_02")
        print("2+2=", add(2, 2))

    def testcase_03(self):
        print("testcase_03")
        print("2+2=", add(3, ))


if __name__ == '__main__':
    unittest.main()

testSuite_demo.py

import  unittest

from test  import  TestCase01,TestCase02,TestCase03

suite = unittest.TestSuite()

# 实例化TestSuite类
suite = unittest.TestSuite()
# 以测试用例类里的每一个方法为单位添加
# suite.addTest(TestCase01("testcase_01"))
# suite.addTest(TestCase01("testcase_02"))
# suite.addTest(TestCase02("testcase_02"))

# 以测试用例类为单位添加
suite.addTest(unittest.makeSuite(TestCase01))
suite.addTest(unittest.makeSuite(TestCase02))

runner = unittest.TextTestRunner()
runner.run(suite)

defaultTestLoader

说明: 
    使用unittest.defaultTestLoader()类,通过该类下面的discover()方法自动搜索指定目录下指定开头
    的.py文件,并将查找到的测试用例组装到测试套件;

用法:
    test_dir = './'
    disconver = unittest.defaultTestLoader.discover(test_dir, pattern='iweb_*.py')
    (test_dir为要指定的目录 ./为当前目录;pattern:为查找的.py文件的格式 )
运行:
    runner=unittest.TextTestRunner()
    runner.run(disconver)
testdefaultTestLoader_demo.py
import unittest

# test_dir为要指定的目录 ./为当前目录;pattern:为查找的.py文件的格式
discover = unittest.defaultTestLoader.discover("./cases", pattern='*.py')

runner = unittest.TextTestRunner()
runner.run(discover)

test01.py

import unittest


class TestCase02(unittest.TestCase):
    # 方法名必须以test开头
    def testcase_01(self):
        print("TestCase02_testcase_01")

    def testcase_02(self):
        print("TestCase02_testcase_02")

    def testcase_03(self):
        print("TestCase02_testcase_03")

test02.py

import unittest


class TestCase02(unittest.TestCase):
    # 方法名必须以test开头
    def testcase_01(self):
        print("TestCase02_testcase_01")

    def testcase_02(self):
        print("TestCase02_testcase_02")
        #self.assertEqual('heo', "hello world")

    def testcase_03(self):
        print("TestCase02_testcase_03")

test03.py

import unittest


class TestCase02(unittest.TestCase):
    # 方法名必须以test开头
    def testcase_01(self):
        print("TestCase02_testcase_01")

    def testcase_02(self):
        print("TestCase02_testcase_02")

    def testcase_03(self):
        print("TestCase02_testcase_03")

defaultTestLoader与TestSuite区别

1. TestSuite可以添加TestCase中所有test开头的方法和添加指定的test开头方法;
2. defaultTestLoader搜索指定目录下指定开头.py文件,并添加TestCase内所有test开头的方法,不能指定添加方法;

提示:defaultTestLoader属于TestSuite另一种实现方式;

UnitTest断言

什么是断言?

概念:让程序代替人为判断测试程序执行结果是否符合预期结果的过程

为什么要学习断言?

自动化脚本在执行的时候一般都是无人值守状态,我们不知道执行结果是否符合预期结果,所以我们需要让程序代替人
为检测程序执行的结果是否符合预期结果,这就需要使用断言;

UnitTest断言分类

1. 基本布尔型断言
2. 比较断言
3. 复杂断言

提示:
    1. 这里这介绍基本布尔类型断言
    2. 比较断言、复杂断言有兴趣的同学请参考4.4附件资料
基本布尔型断言(掌握常用即可)
说明:结果只有True和False
序号断言方法断言描述
1assertEqual(arg1, arg2, msg=None)验证arg1=arg2,不等则fail 【掌握】
2assertNotEqual(arg1, arg2, msg=None)验证arg1 != arg2, 相等则fail
3assertTrue(expr, msg=None)验证expr是true,如果为false,则fail
4assertFalse(expr,msg=None)验证expr是false,如果为true,则fail
5assertIsNone(expr, msg=None)验证expr是None,不是则fail
6assertIsNotNone(expr, msg=None)验证expr不是None,是则fail
7assertIn(arg1, arg2, msg=None)验证arg1是arg2的子串,不是则fail【掌握】

案例

需求:
    1. iweb项目登陆,输入正确用户名和密码,断言登录成功的用户名是否为admin,如果断言失败截图保存

扩展:
    1. 图片名称为动态-时间
    2. 图片名称添加断言错误信息

实现步骤分析

1. 成功登陆
2. 获取登陆后的信息
3. 添加断言

断言主要代码:

...
    # 获取登陆信息
    text = self.driver.find_element_by_css_selector(".loginfo").text
    print("登陆成功信息为:",text)
    try:
        # 使用断言 判断text是否包含admin字符
        self.assertIn("admin",text)
    except AssertionError:
        driver.get_screenshot_as_file("../Image/02img.jpg")
        # 抛出异常
        raise
...

断言.py

import unittest


def add(a, b):
    return a + b


# 继承unittest.TestCase类
class TestCase01(unittest.TestCase):
    # 方法名必须以test开头
    def testcase_01(self):
        print("testcase_01")
        print("1 + 1 = ", add(1, 1))
        try:
            self.assertEqual(2, add(1, 2))
        except AssertionError as e:
            print("报错信息", e)
            raise

    def testcase_02(self):
        print("testcase_02")
        print("2 + 2 = ", add(2, 2))
        try:
            self.assertIn('124', '123456')
        except AssertionError as e:
            print(e)
            raise

    def testcase_03(self):
        print("testcase_03")
        print("3 + 3 = ", add(3, 3))


if __name__ == '__main__':
    unittest.main()
Testing started at 0:07 ...
C:\Users\dengpan\AppData\Local\Programs\Python\Python39\python.exe "D:\softWare\python\tools\PyCharm 2020.1\plugins\python\helpers\pycharm\_jb_unittest_runner.py" --path D:/python_code/自动化测试/断言.py
Launching unittests with arguments python -m unittest D:/python_code/自动化测试/断言.py in D:\python_code\自动化测试

testcase_01
1 + 1 =  2
报错信息  :: 2 != 3


Ran 3 tests in 0.029s

FAILED (failures=2)


3 != 2

Expected :2
Actual   :3
<Click to see difference>

Traceback (most recent call last):
  File "D:\softWare\python\tools\PyCharm 2020.1\plugins\python\helpers\pycharm\teamcity\diff_tools.py", line 32, in _patched_equals
    old(self, first, second, msg)
  File "C:\Users\dengpan\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 831, in assertEqual
    assertion_func(first, second, msg=msg)
  File "C:\Users\dengpan\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 824, in _baseAssertEqual
    raise self.failureException(msg)
AssertionError: 2 != 3

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "C:\Users\dengpan\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 59, in testPartExecutor
    yield
  File "C:\Users\dengpan\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 593, in run
    self._callTestMethod(testMethod)
  File "C:\Users\dengpan\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 550, in _callTestMethod
    method()
  File "D:\python_code\自动化测试\断言.py", line 15, in testcase_01
    self.assertEqual(2, add(1, 2))

testcase_02
2 + 2 =  4
'124' not found in '123456'

Failure
Traceback (most recent call last):
  File "C:\Users\dengpan\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 59, in testPartExecutor
    yield
  File "C:\Users\dengpan\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 593, in run
    self._callTestMethod(testMethod)
  File "C:\Users\dengpan\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 550, in _callTestMethod
    method()
  File "D:\python_code\自动化测试\断言.py", line 24, in testcase_02
    self.assertIn('124', '123456')
  File "C:\Users\dengpan\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 1098, in assertIn
    self.fail(self._formatMessage(msg, standardMsg))
  File "C:\Users\dengpan\AppData\Local\Programs\Python\Python39\lib\unittest\case.py", line 670, in fail
    raise self.failureException(msg)
AssertionError: '124' not found in '123456'

testcase_03
3 + 3 =  6

Process finished with exit code 1

Assertion failed

Assertion failed

Assertion failed

断言总结

1. 什么是断言?
2. 需要掌握哪个断言?
3. 断言异常类
4. 如何获取断言错误信息
5. 时间格式(年_月_日 时_分_秒)

回顾

 1.3 为什么使用UnitTest框架?    
    1. 能组织用例和执行用例
    2. 提供丰富的断言方法
    3. 提供丰富的日志与测试结果

生成HTML测试报告

什么是HTML测试报告

说明:HTML测试报告就是执行完测试用例后以HTML(网页)方式将执行结果生成报告

为什么要生成测试报告

1. 测试报告是本次测试目的最终体现形态
2. 测试报告内包含了有关本次测试用例的详情

HTML生成报告方式

1. Export Test Results (UnitTest 自带)
2. HTMLTestRunner(第三方模板)【重点】

2.1 Export Test Results (自带)

HTMLTestRunner[重点]

HtmlTestRunner安装包

(1). 测试报告 生成步骤分析
1. 复制HTMLTestRunner.py文件到项目文件夹
2. 导入HTMLTestRunner、UnitTest包    
3. discover加载要执行的用例
      (discover=unittest.defaultTestLoader.discover(test_dir,pattern="test*.py"))
4. 设置报告生成路径和文件名
   (file_name=file_dir+nowtime+"Report.html")
5. 打开报告 with open(file_name,'wb') as f:
6. 实例化HTMLTestRunner对象:runner=HTMLTestRunner(stream=f,[title],[description])
    参数说明:
               (stream:文件流,打开写入报告的名称及写入编码格式)
               (
                       [],为可选;
                       title为报告标题,如XXX自动化测试报告
                       description:为说明;比如操作系统、浏览器等版本
               )
7. 执行:runner.run(discover)
(2).实现代码
import time
from CodeEdit.LX04.Tools.HTMLTestRunner import HTMLTestRunner
import unittest
# 加载当前目录
test_dir='.'
# 加载当前目录下iweb开头的.py文件
discover=unittest.defaultTestLoader.discover(test_dir,pattern="test*.py")
if __name__ == '__main__':
    # 定义报告目录
    file_dir="../Report/"
    # 定义报告名称格式
    nowtime=time.strftime("%Y-%m-%d %H_%M_%S")
    # 报告完整路径和名称
    file_name=file_dir+nowtime+"Report.html"
    with open(file_name,"wb")as f:
        # 实例化HTMLTestRunenr对象,传入报告文件流f
        runner=HTMLTestRunner(stream=f,title="iweb_shop项目Web自动化测试报告",description="测试用例共计2条")
        runner.run(discover)

案例:

测试报告.py

from test import TestCase01
from tools.HTMLTestRunner import HTMLTestRunner
import unittest

# 使用suite导入测试用例
# suite = unittest.TestSuite()
# suite.addTest(unittest.makeSuite(TestCase01))

# 使用discover导入测试用例
discover = unittest.defaultTestLoader.discover("./cases", pattern='*.py')

with open("./reports/haha.html", "wb") as f:
    h = HTMLTestRunner(stream=f, title="测试报告", description="windows chrome")
    h.run(discover)

test.py

import unittest


def add(x, y):
    return x + y;


class TestCase01(unittest.TestCase):  # 新建测试类必须继承unittest.TestCase
    def testcase_01(self):
        print("testcase_01")

        print("1+1=", add(1, 1))

    def testcase_02(self):
        print("testcase_02")
        print("2+2=", add(2, 2))

    def testcase_03(self):
        print("testcase_03")
        print("2+2=", add(3, 3))

class TestCase02(unittest.TestCase):  # 新建测试类必须继承unittest.TestCase
    def testcase_01(self):
        print("testcase_01")
        print("1+1=", add(1, 1))

    def testcase_02(self):
        print("testcase_02")
        print("2+2=", add(2, 2))

    def testcase_03(self):
        print("testcase_03")
        print("2+2=", add(3, 3))
class TestCase03(unittest.TestCase):  # 新建测试类必须继承unittest.TestCase
    def testcase_01(self):
        print("testcase_01")
        print("1+1=", add(1, 1))

    def testcase_02(self):
        print("testcase_02")
        print("2+2=", add(2, 2))

    def testcase_03(self):
        print("testcase_03")
        print("2+2=", add(3, 3))


if __name__ == '__main__':
    unittest.main()

3. 总结

1. HTMLTestRunner作用
2. 使用HTMLTestRunner生成报告操作步骤

Fixture

说明:是一个概述,对一个测试用例环境的搭建和销毁就是一个Fixture;
使用:
    1. 初始化(搭建):def setUp(self)        --> 首先执行
       (setUp:此方法继承于unittest.TestCase)        
    2. 结束(销毁):    def tearDown(self)        --> 最后执行
       (tearDown:此方法继承于unittest.TestCase)
提示:
    1. 必须继承unittest.TestCase类,setUp、tearDown才是一个Fixture;
    2. setUp:一般做初始化工作,比如:实例化浏览器、浏览器最大化、隐式等待设置
    3. tearDown:一般做结束工作,比如:退出登录、关闭浏览器
    4. 如果一个测试类有多个test开头方法,则每个方法执行之前都会运行setUp、结束时运行tearDown

案例

fixture_demo.py

# 导包
import unittest


def add(a, b):
    return a + b


# 继承unittest.TestCase类
class TestCase01(unittest.TestCase):
    # 在每条用例执行前执行
    def setUp(self):
        print("setUp")

    # 在每条用例执行后执行
    def tearDown(self):
        print("tearDown")

    # 方法名必须以test开头
    def testcase_01(self):
        print("testcase_01")
        print("1 + 1 = ", add(1, 1))
        # self.assertEqual(2, add(1, 2))

    def testcase_02(self):
        print("testcase_02")
        print("2 + 2 = ", add(2, 2))

    def testcase_03(self):
        print("testcase_03")
        print("3 + 3 = ", add(3, 3))


class TestCase02(unittest.TestCase):
    # 方法名必须以test开头
    def testcase_01(self):
        print("TestCase02_testcase_01")

    def testcase_02(self):
        print("TestCase02_testcase_02")

    def testcase_03(self):
        print("TestCase02_testcase_03")


if __name__ == '__main__':
    unittest.main()
Testing started at 0:24 ...
C:\Users\dengpan\AppData\Local\Programs\Python\Python39\python.exe "D:\softWare\python\tools\PyCharm 2020.1\plugins\python\helpers\pycharm\_jb_unittest_runner.py" --path D:/python_code/自动化测试/fixture_demo.py
Launching unittests with arguments python -m unittest D:/python_code/自动化测试/fixture_demo.py in D:\python_code\自动化测试

setUp
testcase_01
1 + 1 =  2
tearDown
setUp
testcase_02
2 + 2 =  4
tearDown
setUp
testcase_03
3 + 3 =  6
tearDown
TestCase02_testcase_01
TestCase02_testcase_02
TestCase02_testcase_03


Ran 6 tests in 0.032s

OK

Process finished with exit code 0

附件-断言资料

基本布尔型断言

序号断言方法断言描述
1assertEqual(arg1, arg2, msg=None)验证arg1=arg2,不等则fail 【常用】
2assertNotEqual(arg1, arg2, msg=None)验证arg1 != arg2, 相等则fail
3assertTrue(expr, msg=None)验证expr是true,如果为false,则fail 【常用】
4assertFalse(expr,msg=None)验证expr是false,如果为true,则fail 【常用】
5assertIs(arg1, arg2, msg=None)验证arg1、arg2是同一个对象,不是则fail
6assertIsNot(arg1, arg2, msg=None)验证arg1、arg2不是同一个对象,是则fail
7assertIsNone(expr, msg=None)验证expr是None,不是则fail
8assertIsNotNone(expr, msg=None)验证expr不是None,是则fail
9assertIn(arg1, arg2, msg=None)验证arg1是arg2的子串,不是则fail
10assertNotIn(arg1, arg2, msg=None)验证arg1不是arg2的子串,是则fail
11assertIsInstance(obj, cls, msg=None)验证obj是cls的实例,不是则fail
12assertNotIsInstance(obj, cls, msg=None)验证obj不是cls的实例,是则fail

比较断言

序号断言方法断言描述
1assertAlmostEqual (first, second, places = 7, msg = None, delta = None)验证first约等于second。 palces: 指定精确到小数点后多少位,默认为7
2assertNotAlmostEqual (first, second, places, msg, delta)验证first不约等于second。 palces: 指定精确到小数点后多少位,默认为7 注: 在上述的两个函数中,如果delta指定了值,则first和second之间的差值必须≤delta
3assertGreater (first, second, msg = None)验证first > second,否则fail
4assertGreaterEqual (first, second, msg = None)验证first ≥ second,否则fail
5assertLess (first, second, msg = None)验证first < second,否则fail
6assertLessEqual (first, second, msg = None)验证first ≤ second,否则fail
7assertRegexpMatches (text, regexp, msg = None)验证正则表达式regexp搜索匹配的文本text。 regexp:通常使用re.search()
8assertNotRegexpMatches (text, regexp, msg = None)验证正则表达式regexp搜索不匹配的文本text。 regexp:通常使用re.search() 说明:两个参数进行比较(>、≥、<、≤、约等、不约等)

复杂断言

序号断言方法断言描述
1assertListEqual(list1, list2, msg = None)验证列表list1、list2相等,不等则fail,同时报错信息返回具体的不同的地方
2assertTupleEqual (tuple1, tuple2, msg = None)验证元组tuple1、tuple2相等,不等则fail,同时报错信息返回具体的不同的地方
3assertSetEqual (set1, set2, msg = None)验证集合set1、set2相等,不等则fail,同时报错信息返回具体的不同的地方
4assertDictEqual (expected, actual, msg = None验证字典expected、actual相等,不等则fail,同时报错信息返回具体的不同的地方

实战案例 

需求:使用UnitTest框架对iweb_shop项目测试
    1. 登陆进行测试

iwebshop_login_test_run.py
import unittest

from iwebshop_login_testcase import IwebshopLoginTest
from tools.HTMLTestRunner import HTMLTestRunner

suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(IwebshopLoginTest))

with open("./reports/iwebshop_login_test_report.html", "wb") as f:
    h = HTMLTestRunner(stream=f, title="iwebshop登录模块自动化测试报告", description="windows10 chrome")
    h.run(suite)

 iwebshop_login_testcase.py

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


class IwebshopLoginTest(unittest.TestCase):
    # 前期准备工作
    def setUp(self):
        self.driver = webdriver.Chrome()
        self.driver.maximize_window()
        self.driver.implicitly_wait(30)
        self.driver.get(r"http://www.web.com/")
        # time.sleep(1)

    # 测试完收尾工作
    def tearDown(self):
        self.driver.quit()

    def test_login(self):
        # 定位登录按钮
        self.driver.find_element(By.LINK_TEXT,"登录").click()
        # 定位输入框
        self.driver.find_element(By.NAME,"login_info").send_keys("test")
        self.driver.find_element(By.NAME,"password").send_keys("123456")
        # 定位登录提交按钮
        self.driver.find_element(By.CLASS_NAME,"submit_login").click()
        # 保存登录后用户信息,以便断言使用
        login_info = self.driver.find_element(By.CLASS_NAME,"loginfo").text
        try:
            # 执行断言操作
            self.assertIn("test", login_info)
        except AssertionError as e:
            print("登录失败")
            # 如果断言失败,截图并保存
            self.driver.get_screenshot_as_file("./images/%s.png" % str(time.time()).replace(".", "_"))
            raise

    def test_login_error(self):
        self.driver.find_element(By.LINK_TEXT,"登录").click()
        self.driver.find_element(By.NAME,"login_info").send_keys("test1")
        self.driver.find_element(By.NAME,"password").send_keys("123456")
        self.driver.find_element(By.CLASS_NAME,"submit_login").click()
        login_info = self.driver.find_element(By.CLASS_NAME,"loginfo").text
        try:
            self.assertIn("test1", login_info)
        except AssertionError as e:
            print("登录失败")
            self.driver.get_screenshot_as_file("./images/%s.png" % str(time.time()).replace(".", "_"))
            raise

  • 27
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

人生如梦亦如幻唯心在

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值