学习交流微信:AllenAi1877
一、什么样的项目需要做自动化测试:
1、需求变动不频繁
2、项目周期长
3、项目需要回归测试二、什么阶段开始:
功能测试完毕(手工测试)三、web自动化测试所属分类:
1、黑盒测试(功能)-----自动化属于这个
2、白盒测试(单元)
3、灰盒测试(接口)web自动化测试用例:跟着功能测试的用例后面加上“是否自动化”四、安装selenium包1****很重要的:pip包管理工具按Ctrl+r跑出cmd的运行窗口,然后输入pip install selenium  就会安装最新版本的selenium
安装完后可以输入pip show selenium来查看版本等信息
可以输入 pip uninstall selenium来卸载扩展:
pip install selenium==版本号来指定安装的版本
在==号后面输入一个错误的版本号按回车,会提示所有可以安装的版本号
==号后面抄一个正确的版本就可以了pip是python中的包管理工具(可以安装、卸载、查看python工具)-------需要先安装好python3的运行环境
必须连网才能使用Pip
pip list:查看通过pip工具安装的插件或工具2、可以通过pycharm来安装
推荐原因:安装到当前工程环境里
操作:File--setting--Project:当前工程名称---Project Interpreter--点击+号安装相应包和版本
提示:如果使用pip install 插件名  安装过后,打开pycharm,导包操作时,提示找不到此包,那就
说明使用pip install 默认安装 的路径和当前工程所有的环境路径不是同一个环境,进行以上处理即可
安装浏览器驱动
firefox  48以上版本   需要selenium 3.x+firefox驱动(geckodriver)
下载地址:https://github.com/mozilla/geckodriver/releases/
里面有各个版本的驱动,有相对应的firefox版本驱动和浏览器版本是对应的,下载哪一个要去官网查看
google
http://chromedriver.storage.googleapis.com/index.html应用:
将浏览器驱动放到指定文件夹
将浏览器驱动所在目录添加到系统path环境变量中科普path:
如果在cmd里面输入命令时提示不是内部命令,一般都是path这里没设置好
说明:指定系统搜索的目录
dos命令默认搜索顺序:1、检测是否为内部命令    2、检测是否为当前目录下可执行文件
3、检测path环境变量指定的目录
提示:
1、如果 以上搜索目录都检测不到输入的命令或或执行文件,系统会抛出不是内部或外部命令。。。
2、在web环境中,如果不将浏览器驱动添加到path中,selenium在运行的时候会提示浏览器驱动有误# 第一个selenium案例:
# 需求:打开百度首页并停留3秒后关闭浏览器驱动
#1、导包
from selenium import webdriver
from time import sleep
#获取浏览器驱动
driver=webdriver.Chrome()
#打开url
driver.get("http://baidu.com")
#暂停3秒
sleep(3)
#关闭浏览器驱动
driver.quit();五、元素定位
工具:
Firefox        Firebug(F12获取)
谷歌    F12元素定位依赖于:1、标签名 2、属性 3、层级 4、路径
定位方式:
元素属性
1id
2、name
3、class_name
标签
4、tag_name
a标签 (可点击文本)
5、link_text(定位超连接 a标签)
6、partial_link_text(同上,可模糊)7、XPath(基于元素路径)
8、CSS(元素选择器)1id定位
element=driver.find_element_by_id(id)例子:
from selenium import webdriver
from time import sleep; #如果直接import time会把time的所有方法都导进来,不好#快速导包:输入sleep后,按ctrl+alt+空格,然后选中想要的方法后回车,就直接导包成功了
driver=webdriver.Firefox();
#如果输入的是本地文件的url,例如E:\aaa\bbb\ccc\index.html
#里面有\反斜杆,其在python中是转义字符。此时可以写成url=r"E:\aaa\bbb\ccc\index.html"  r是装饰的字符串,如果字符串中有转义字符,不进行转义使用
#也可以不用r,直接写2个\\      E:\\aaa\\bbb\\ccc\\index.html
#使用本地浏览器模式 前缀必须添加file:///
#url="file:///E:/aaa/bbb/ccc/index.html"
url='http://www.baidu.com'
driver.get(url);
driver.maximize_window();
driver.find_element_by_class_name('engine-key-wrapper').send_keys('python');
driver.find_element_by_id('search-submit').click();
sleep(3)
driver.quit();2、name定位
element=driver.find_element_by_name(name)  #name是用引号括起来的3、class_name定位
element=driver.find_element_by_class_name(classname)4、tag_name定位    标签即是元素  例如input  div a 等      很少用
element=driver.find_element_by_tag_name(tag_name)如果找到多个同样的的标签,默认返回第一个5、link_text定位和partial_link_text定位        封装的时候一般使用后者
都是定位a标签,但是partial_link_text可以模糊定位,即不用全部匹配,前者需要
element=driver.find_element_by_link_text(text)        # 引号内部的文字如果不是全部匹配则会报错
element=driver.find_element_by_partial_link_text('123').click();  #只有是包含123的字符的就可以click了。但是最好使用能代表唯一性的词,如果有多个,还是返回第一个7、XPath     XML Pathelement=driver.find_element_by_xpath(xpath)定位策略(方式)
1)路径     看7.1路径定位
2)利用元素属性     比如//input[@id='password']    这是相对路径定位时,可能会找到多个input,此时考虑结合属性来定位,需要[@]
3)属性加上逻辑           比如//input[@class='login' and @name='user-test']         当使用一个属性class找到的还不是唯一时,需要使用and 来多加一个属性来找
4)层级与属性结合       比如://p[@id='login-T2']/input[@name='user' and @type='text']    当使用2个属性都找不到唯一时,给它加上父层级路径       第一次要//,第二级就只要/一般使用子级的属性找不到唯一,就加上父级的属性,然后把子级的属性去掉://p[@id='login-T2']/input7.1 路径定位(绝对 、相对路径)
绝对路径:从最外层元素到指定元素之间所有经过元素层级的路径
1)绝对路径以/html根节点开始,使用/来隔元素层级:
/html/body/div/fieldset/p[1]/input
2)绝对路径对页面结构要求比较严格,不建议使用相对路径:匹配任意层级的元素,不限制元素的位置
1)相对路径以//开始
2)格式://input       或者  //*7.2  XPath延申
//*[text()='xxx']           文本内容是xxx的元素
driver.find_element_by_xpath("//*[text()='开课/合作']").click();//*[contains(@attribute,'xxx')]      属性中含有xxx的元素        移动端全是这样子写,重要
driver.find_element_by_xpath("//*[contains(@id,'keyword')]").send_keys('python');//*[starts-with(@attribute,'xxx')]      属性以xxx开头的元素
driver.find_element_by_xpath("//*[starts-with(@id,'js_sea')]").click();8、CSS定位方法
element=driver.find_element_by_css_selector(css_selector)
8.1、常用策略
1) id选择器        #id
2class选择器   .class
3)元素选择器    input       直接写属性名称
4)属性选择器    [name='passwordA']
5)层级选择器   p>input      或者 p input          两者的区别:p一定是input的直接上级,后者则不一定是直接上级,不管中间隔多少级p#idname>input       id名称为idname的p下面的inputdriver.find_element_by_css_selector('.header-index-text p').click();      层级与元素选择器、class选择器结合使用CSS 元素选择器 定位span(这个是任意标签名)标签获取文本值
下面就是打印出class=mnav的标签的文本
ps=driver.find_element_by_css_selector('.mnav').text;
print('文本值是:',ps)       #文本值是: 抗击肺炎8.2  CSS 延申
input[type^='p']   type属性以p字母开头的元素
input[type$='d']   type属性以d字母结束的元素
input[type*='w']    type属性包含d字母的元素8.3 定位一组元素
dirver.find_elements_by_id#以下是定位到一组以mnav为class名的元素列表,打印其长度为7
elements=driver.find_elements_by_css_selector('.mnav')
print(len(elements));
#那么要对其中一个进行操作,需要以下标的方式
elements[1].click();#通过遍历来操作,假设是文本框,全部输入同一个文字信息
for el in elements:el.send_keys('我是同一个文字信息');8.4  find_element方法封装# 需求:使用driver_element方法来定位driver.find_element(By.ID,'kw').send_keys('python');driver.find_element(By.CSS_SELECTOR,'#su').click();By类:需要导包位置   输入By之后,按ctrl+alt+空格可以快速导包from selenium.webdriver.common.by import By六、元素操作方法
1、目的:
1)需要让脚本模拟用户级指定元素插入值
2)模拟人为删除元素的内容
3)模拟点击操作2、方法
1) click()    单击元素
2)send_keys(value)  模拟输入
3)clear() 清除文本3、案例
需求:输入文本后清空、修改再提交
driver.find_element_by_css_selector('#kw').send_keys("python");
sleep(3);
driver.find_element_by_css_selector('#kw').clear();
driver.find_element_by_css_selector('#kw').send_keys("java");
sleep(3)
driver.find_element_by_css_selector('#su').click();七、浏览器操作方法
最大化  maximize_window()
设置大小 set_window_size(width,height)
窗口位置  set _window_position(x,y)
后退   back()
前进   forward()
刷新 F5  refresh()
关闭当前窗口 close()
关闭由driver启动的所有窗口  quit()
获取页面的title  title
获取当前的url  current_url
提示:最后两个,没有括号,应用场景:一般为判读上步操作是否成功实例:from selenium import webdriver;
from time import sleep;
driver=webdriver.Firefox();
# driver._is_remote = False
url='http://www.baidu.com';
driver.get(url);
#将浏览器最大化
driver.maximize_window();
sleep(5)
# 设置固定大小300、200
# driver.set_window_size(300,200);
# sleep(2)
# 移动浏览器窗口位置 x:320   y:150
# driver.set_window_position(320,150)
# sleep(2)# 最大化
# driver.maximize_window();
# 点击访问另一个访问,演示后退功能
driver.find_element_by_name('tj_trnews').click();
# driver.find_element_by_css_selector('').click();
sleep(2)
driver.back();
sleep(2)
# 然后演示前进功能
#driver.forward();
#sleep(3);
driver.find_element_by_css_selector('#kw').send_keys('python');
sleep(3);
#刷新
driver.refresh();
#获取当前页面title
title=driver.title;
print('当前页面的title是:',title);
sleep(3)
#获取当前页面url
current_url=driver.current_url;
print('当前页面的url是:',current_url);
sleep(3);
driver.find_element_by_partial_link_text('关于百度').click();
sleep(3);
driver.close();
sleep(3);
driver.quit();八、获取元素信息
1、元素的文本
2、元素的属性值    作用:检测属性值的正确与否、  利用属性值判断是否我们要的元素
3、判断元素是否可见状态常用方法
1、size  返回元素大小
2、text  获取元素的文本          size和text是属性,调用时无括号:xxx.size
3、get_attribute('xxx') 获取属性值,传递的参数为元素的属性名
4、is_displayed()    判断元素是否可见
5、is_enabled()    判断元素是否可用
6、is_selected()     判断元素是否选中,用来检查复选框或单选按钮是否被选中实例:
from selenium import webdriver;
from time import sleep;
driver=webdriver.Firefox();
# driver._is_remote = False
url='http://www.baidu.com';
driver.get(url);
#将浏览器最大化
driver.maximize_window();
#获取输入框的大小
# 获取页面上某个超连接的文本内容
# 获取页面上第一个超链接的地址
# 判断页面中的某标签是否可见
# 判断页面中的某按钮是否可用
# 判断页面f中的复选框是否为选中的状态
size=driver.find_element_by_css_selector('#kw').size;
print('输入框的大小是:',size);
texts=driver.find_element_by_css_selector('#virus-2020').text;
print('页面中id为virus-2020的元素的文字为:',texts);
att=driver.find_element_by_css_selector('a').get_attribute('text')
print('页面中id是kw的属性是:',att);
display=driver.find_element_by_css_selector('#su').is_displayed();
print('搜索按钮是否可见:',display);#结果是True或者False
enabled=driver.find_element_by_css_selector('#su').is_enabled();
print('搜索按钮是否可用:',enabled);#结果是True或者False
# selected=driver.find_element_by_css_selector('xxx').is_selected();
# print('xxx是否被选中',selected);
driver.quit();结果是:
输入框的大小是: {'width': 548.0, 'height': 44.0}
页面中id为virus-2020的元素的文字为: 抗击肺炎
页面中id是kw的属性是: 百度首页
搜索按钮是否可见: True
搜索按钮是否可用: True九、键盘和鼠标操作
鼠标:点击、右击、双击、悬停、拖拽
1、鼠标操作的方法
说明:在Selenium中将操作鼠标的方法封闭在ActionChains 类中
实例化对象:action=ActionChains(driver)
方法:
1) context_click(element)  右击
2)   double_click(element)   双击
3)drag_and_drop(source,target) 拖动
4)  move_to_element(element)  悬停
5)  perform()   执行                 ------>此方法用来执行以上所有鼠标操作提示:selenium框架中虽然提供了右击鼠标的方法,但是没有提供选择右击菜单方法,可以通过发送快捷键的方式解决(但是chrome浏览器不支持这种方法)实例:
from selenium import webdriver;
from time import sleep;from selenium.webdriver import ActionChainsdriver=webdriver.Chrome();
# driver._is_remote = False
url='http://www.baidu.com';
driver.get(url);
#将浏览器最大化
driver.maximize_window();
#首先实例化并获取ActionChains类           先输入ActionChains然后按ctrl+alt+空格键导包from selenium.webdriver import ActionChains
action=ActionChains(driver);
#在文本框里右击,  预期:出现“粘贴”功能
# action.context_click(driver.find_element_by_css_selector('#kw')).perform();
# sleep(5)#先手动复制一个文本,然后使用发送右键快捷键的方式粘贴一个内容
serchtext=driver.find_element_by_css_selector('#kw');
action.context_click(serchtext).perform();
serchtext.send_keys('p');#p是右键菜单粘粘的快键键
#在文本框里输入文字后双击   预期:全选中
ele=driver.find_element_by_css_selector('#kw');
action.context_click(ele).perform();
#移动到超连接后悬停     预期:超连接文字变色
action.move_to_element(driver.find_element_by_css_selector('#virus-2020')).perform();
sleep(5);
action.double_click(driver.find_element_by_css_selector('#kw').send_keys('python')).perform();
sleep(5)
driver.find_element_by_css_selector('#virus-2020').click();
sleep(5)#拖拽
sourse=driver.find_element_by_css_selector('#div1');#源元素;假设是一个红色盒子
target=driver.find_element_by_css_selector('#div2');#目标元素
action.drag_and_drop(sourse,target).perform();
#拖拽扩展
action.drag_and_drop_by_offset(sourse,xoffset=360,yoffset=180);#拖动往x轴360个像素,y轴180个像素driver.quit();2、键盘操作
#Selenium中把键盘按钮都封装在keys类中1)删除键(BackSpace)      send_keys(Keys.BACK_SPACE)
2)空格键(Space)    send_keys(Keys.SPACE)
3)制表键(Tab)        send_keys(Keys.TAB)
4)回退键(Esc)        send_keys(Keys.ESCAPE)
5)  回车键(Enter)        send_keys(Keys.ENTER)
6)全选(Ctrl+A)        send_keys(Keys.CONTROL,'a')
7)复制(Ctrl+C)        send_keys(Keys.CONTROL,'c')实例:
from selenium import webdriver;
from time import sleep;
from selenium.webdriver.common.keys import Keys;
driver=webdriver.Chrome();
url='http://www.baidu.com'
driver.get(url);
"""
需求
输入框里输入python1
删除1
全选 复制 python
粘贴
"""
serchtext=driver.find_element_by_css_selector('#kw');
serchtext.send_keys('python1');
sleep(3);
serchtext.send_keys(Keys.BACK_SPACE);
sleep(3)
serchtext.send_keys(Keys.CONTROL,'a');
serchtext.send_keys(Keys.CONTROL,'c')
sleep(3)
serchtext.send_keys(Keys.CONTROL,'v')
sleep(3)
driver.find_element_by_css_selector('#su').click();
sleep(5)
driver.quit();十一、元素等待
由于电脑配置或网络原因,在查找元素时,元素代码未在第一时间内被 加载出来,而抛出未找到元素异常
概念:元素在第一次未找到时,元素等待设置的时长被激活,如果在设置的有效时长内找到元素,继续执行代码,如果超出设置的时间未找到元素,抛出未找到元素异常
分类:
隐式等待:定位元素时,如果能定位到元素则直接返回元素,不触发等待;如果不能定位到该元素,则间隔一段时间后再去定位元素;如果在达到最大时长还没找到指定元素,则抛出不存在的异常 NoSuchElementException
现实方式:
driver.implicitly_wait(timeout)            单位是秒。实际工作中一般设置为30秒,但是如果是新浪网实种网页,直接设置80秒
实例:
from selenium import webdriver;
from time import sleep;
from selenium.webdriver.common.keys import Keys;
driver=webdriver.Chrome();
#设置隐式等待10秒。
# 特色:1、设置在全局中,针对所有元素有效 2、一般情况下为前置必写代码(1)获取浏览器驱动对象;2)最大化浏览器;3)设置等待)
driver.implicitly_wait(10);
url='http://www.baidu.com'
driver.get(url);
"""
需求
隐式等待使用
给一个错误的Id,不能知道,如果直接抛出异常,说明等待失败,如果在设置的时间外抛出异常则说明等待设置成功
"""
serchtext=driver.find_element_by_css_selector('#kw');
serchtext.send_keys('python1');
sleep(3);
driver.find_element_by_css_selector('#su').click();
sleep(5)
driver.quit();显式等待:
定位元素时,如果能定位到元素则直接返回元素,不触发等待;如果不能定位到该元素,则间隔一段时间后再去定位元素;如果在达到最大时长还没找到指定元素,则抛出异常 TimeoutException
在Selenium中把显式等待的相关方法封装在WebDriverWait 类中现实方式:
1、导包  等待类
from selenium.webdriver.support.wait import WebDriverWait;
2、实例化
WebDriverWait(driver,timeout=30,poll_frequency=0.5)
1)driver:浏览器驱动对象
2)timeout:超时时长,单位:秒
3)poll_frequency:检测间隔时间:默认为0.5秒,可以改为任意秒
3、调用方法
until(method):直到。。。时
1)method:函数名称,该函数用来实现对元素的定位
2)一般使用匿名函数来实现:lanbda x:x.find_element_by_id('kw')
4、element=WebDriverWait(driver,10,1).until(lambda x:x.find_element_by_id('kw'))
#x:x为driver,它是webDriverWait类将传入的driver赋值给类self._driver,until方法调用了self._driver;
提示:WebDriverWait(driver,timeout=30,poll_frequency=0.5).until(lambda x:x.find_element_by_id('kws'))返回一个元素
实例:
from selenium import webdriver;
from time import sleep;
from selenium.webdriver.common.keys import Keys;
driver=webdriver.Chrome();
#导显式等待的包
from selenium.webdriver.support.wait import WebDriverWait;
url='http://www.baidu.com'
driver.get(url);
#实例化WebDriverWait()并调用
#注意:调用until方法返回的一定是一个元素
el=WebDriverWait(driver,timeout=30,poll_frequency=0.5).until(lambda x:x.find_element_by_id('kws'));
el.send_keys('python');#注意:此时el还不是元素,只有代码运行起来的时候才是元素,所以写el.不会弹出send_keys();
sleep(3)
"""
需求
显式等待使用
给一个错误的Id,不能知道,如果直接抛出异常,说明等待失败,如果在设置的时间外抛出异常则说明等待设置成功
"""driver.find_element_by_css_selector('#su').click();
sleep(5)
driver.quit();显式等待和隐式等待的区别:
1、显式等待:针对单个元素生效
2、隐式等待:针对全局元素生效十二、扩展:上传文件from selenium import webdriver;
from time import sleep;
from selenium.webdriver.common.keys import Keys;
driver=webdriver.Chrome();
url='http://www.baidu.com'
driver.get(url);
"""
需求:点击上传文件按钮,可以选择文件上传的
错误思路:
假设【浏览】按钮的name是upfile
driver.find_element_by_css_selector("[name='upfile']").click()
这种思路,点开浏览按钮后弹出的窗口不是浏览器了,无法操作上传文件
"""
#正确的实现方式:使用send_keys('文件路径及文件名')
driver.find_element_by_css_selector("[name='upfile']").send_keys('D:\hello123.txt');#这样子就能上传成功了
sleep(5)
driver.quit();十三、使用CSS定位下拉框  select标签   option
实例:
方式一:
from selenium import webdriver;
from time import sleep;
driver=webdriver.Chrome();
url='https://mail.163.com/register/index.htm?from=163mail';
driver.get(url);
driver.maximize_window();
driver.implicitly_wait(30);
"""
需求:163邮箱注册页面,下拉选择框默认选中163.com
暂停2秒
1、定位 126.com 然后暂停2秒
2、定位yeah.net
"""
driver.find_element_by_css_selector('#username').send_keys('wushuirong_123');
driver.find_element_by_css_selector('.domain').click();
sleep(2);
driver.find_element_by_css_selector("[data-value='126.com']").click();
sleep(2);
driver.find_element_by_css_selector('.domain').click();
driver.find_element_by_css_selector("[data-value='yeah.net']").click();
sleep(2)
driver.quit();方式二、使用Select方法
步骤:
1、导包 Select类  from selenium.webdriver.support.select import Select;
2、获取Select对象匿名:Select(element).select_by_index()   #通过下标实名:select=Select(element)调用:select.select_by_index();
注意:
1、Select类是通过select标签来控制其下的option元素
2、element:只能是select标签
3、实例化select时,需要的参数为select标签元素
4、调用Select类下面的方法,是通过索引、value值或显示文本去控制,而不需要click()事件。element:标签对应的元素,通过元素定位方式获取,例如:
driver.find_element_by_id('selectA')操作方式:
1、select_by_index(index)              根据option索引来定位,从0开始
2、select_by_value(value)            根据option属性value值定位
3、select_by_visible_text(text)       根据option显示文本来定位实例:
from selenium import webdriver;
from time import sleep;
from selenium.webdriver.support.select import Select;
driver=webdriver.Chrome();
url='暂时没有实例连接';
driver.get(url);
driver.maximize_window();
driver.implicitly_wait(30);
"""
假设代码是这样子的:北京上海广州重庆需求是:
暂停2秒
1、定位 上海
2、暂停2秒
3、定位广州
"""
sleep(2)
#通过下标形式访问
Select(driver.find_element_by_css_selector('#selectA')).select_by_index(1);
sleep(2)
Select(driver.find_element_by_css_selector('#selectA')).select_by_index(2);
sleep(2)
#通过value值形式访问
Select(driver.find_element_by_css_selector('#selectA')).select_by_value('sh');
sleep(2)
Select(driver.find_element_by_css_selector('#selectA')).select_by_value('gz');
#通过文本值形式访问
Select(driver.find_element_by_css_selector('#selectA')).select_by_visible_text('上海');
sleep(2)
Select(driver.find_element_by_css_selector('#selectA')).select_by_visible_text('广州');
driver.quit();十四、弹出框
1、alert      警告
2、confirm  确认
3、prompt  提示弹出框如果不关闭会使得后面的操作不生效
处理方法:Selenium中对处理弹出框的操作,有专用的处理方法,并且处理的方法是同一个,即alert\confirm\prompt均使用以下方法1、获取弹出框对象:
alert=driver.switch_to.alert
2、调用
alert.text       #返回alert/confirm/prompt中的文字信息
alert.accept()   #接受对话框选选
alert.dismiss()  # 取消圣诞框选项提示:无论以上哪个对话框,都可以使用取消,同意,因为调用的是后台的事件,跟页面显示的按钮数量无关。
注意:
1、driver.switch.to.alert   方法适合以上三种对话框,调用时没有括号。
2、获取文本的方法,调用时没有括号,如alert.text
3、在项目中不是所有的小窗口都是以上三种对话框
实例:
from selenium import webdriver;
from time import sleep;
driver=webdriver.Chrome();
url='F:/python/hmtlfile/alert.html';
driver.get(url);
driver.maximize_window();
"""
需求:
1、点击alert按钮
2、关闭警告框
3、输入用户名admin
"""
# driver.find_element_by_css_selector("[value='alert警告框']").click();
#driver.find_element_by_css_selector("[value='confirm确认框']").click();
driver.find_element_by_css_selector("[value='prompt提示框']").click();
sleep(3)
#必须切换到弹出框并将其关闭
alert=driver.switch_to.alert;
print('警告框文本是:',alert.text);
alert.accept();
#alert.dismiss();  #取消
alert.
driver.find_element_by_css_selector('.user').send_keys('admin');
sleep(3);
driver.quit();十五、滚动条操作
1、在HTML页面中,由于前端技术框架的原因,页面元素为动态显示,元素根据滚动条的下拉而被加载
2、页面注册同意条款,需要滚动条到最底层,才能点击同意实现方式:
selenium中并没有直接提供操作滚动条的方法,但是可以通过js脚本来达到,例如:
1、设置JavaScript脚本控制滚动条
js='window.scrollTo(0,1000)';
2、然后设用js方法
driver.execute_script(js);实例:
from selenium import webdriver;
from time import sleep;
driver=webdriver.Chrome();
url='F:/python/hmtlfile/alert.html';
driver.get(url);
driver.maximize_window();
"""
需求:
1、打开网页,停留2秒
2、拉到最底下
"""
js='window.scrollTo(0,1000)';   #这个0是左边距,即水平滚动条,1000是上边距,即垂直滚动条,一般设到1000像素都会拉到最底下了,如果页面特别长则需要设得大一点,10000都行
driver.execute_script(js);
sleep(3)
driver.quit();十六、frame切换、多窗口切换(特别重要,每个项目都要用到)
1、frame切换
frame:HTML页面中的一种框架,主要作用是在当前页面中指定区域显示另一个页面的元素:
形式一:[了解]形式二:2、切换方法
1)drivier.switch_to.frame(frame_reference)            ---->切换到指定frame的方法frame_reference:   可以为frame框架的name、id或者定位到frame元素
2)driver.switch_to.default_content();    -->切换回默认页面在frame中操作其他页面,必须先回到默认页面,才能进行下一步操作实例:
from selenium import webdriver;
from time import sleep;
driver=webdriver.Chrome();
url='F:/python/hmtlfile/iframe.html';
driver.get(url);
driver.maximize_window();
"""
需求:
1、在主页面输入用户名
2、在frame1页面中输入用户名
3、在frame2页面中输入用户名
"""
#在主页面输入用户名
driver.find_element_by_css_selector(".names").send_keys('admin');
sleep(2)
#切换到第一个frame并输入用户名
driver.switch_to.frame('frame1');          #这个参数可以是name\id,也可以是iframe元素,例如:
#driver.switch_to.frame(driver.find_element_by_css_selector("[name='frame2']"));
driver.find_element_by_css_selector('.user').send_keys('我是frame1');
sleep(2)
#需要返回主页面才能切换到另一个frame
driver.switch_to.default_content();
#切换到第二个frame
driver.switch_to.frame('frame2');
driver.find_element_by_css_selector('#username').send_keys('我是frame2');
sleep(3)
driver.quit();2、多窗口切换
在Selenium中封装了获取当前窗口句柄、获取所有窗口句柄和切换到指定句柄窗口的方法:
句柄:handle,窗口的唯一识别码
方法:
1)driver.current_window_handle   --->获取当前窗口句柄
2)driver.window_handles        --->获取 所有窗口句柄
3)driver.switch_to.window(handle)  --->切换指定句柄窗口步骤:
1、获取当前窗口句柄
2、点击连接,启动另一个窗口
3、获取当前所有窗口句
4、遍历所有窗口句柄5、判断当前遍历的窗口句柄不等于当前窗口句柄6、切换
7、返回主窗口
8、再次进入别的窗口实例
from selenium import webdriver;
from time import sleep;
driver=webdriver.Chrome();
url='F:/python/hmtlfile/windows.html';
driver.get(url);
driver.maximize_window();
"""
需求:
1、在主页面输入用户名
2、在新窗口页面1中输入用户名
3、在新窗口页面2中输入用户名
"""
#获取当前窗口句柄     --->目的:判断只要不是当前主窗口句柄,就一定是新开的窗口句柄
curren_handle=driver.current_window_handle;
#在主页面输入用户名
driver.find_element_by_css_selector(".names").send_keys('admin');
sleep(2)
driver.find_element_by_partial_link_text('弹窗页面').click();
#获取所有窗口句柄     这句话的位置不能变
handles=driver.window_handles;
#判断  不是 当前窗口句柄
for h in handles:   #  h是随便起的变量,表示句柄,该句柄如果包含在所有句柄(handles)中if h !=curren_handle:   #如果不是当前句柄,则:#切换driver.switch_to.window(h);#切换到第二个窗口并输入用户名
driver.find_element_by_css_selector('.user').send_keys('我是frame1');
sleep(3)
#driver.close();
driver.switch_to.window(curren_handle);
driver.find_element_by_css_selector(".names").send_keys('admin1');
driver.find_element_by_partial_link_text('登录注册页面').click();
handles=driver.window_handles;
for h in handles:   #  h是随便起的变量,表示句柄,该句柄如果包含在所有句柄(handles)中if h !=curren_handle:   #如果不是当前句柄,则:#切换driver.switch_to.window(h);driver.find_element_by_css_selector('#username').send_keys('我是第三个窗口的')
sleep(3)
driver.quit();切换窗口的方法函数封装起来,要用的时候调用的版本:from selenium import webdriver;
from time import sleep;
driver=webdriver.Chrome();
url='F:/python/hmtlfile/windows.html';
driver.get(url);
driver.maximize_window();
"""
需求:
1、在主页面输入用户名
2、在新窗口页面1中输入用户名
3、在新窗口页面2中输入用户名
"""
#获取当前窗口句柄     --->目的:判断只要不是当前主窗口句柄,就一定是新开的窗口句柄
curren_handle = driver.current_window_handle;
def handless():handles = driver.window_handles; #获取所有窗口句柄     这句话的位置不能变# 判断  不是 当前窗口句柄for h in handles:  # h是随便起的变量,表示句柄,该句柄如果包含在所有句柄(handles)中if h != curren_handle:  # 如果不是当前句柄,则:# 切换driver.switch_to.window(h);#在主页面输入用户名
driver.find_element_by_css_selector(".names").send_keys('admin');
sleep(2)
driver.find_element_by_partial_link_text('弹窗页面').click();
handless();#切换到第二个窗口并输入用户名
driver.find_element_by_css_selector('.user').send_keys('我是frame1');
sleep(3)
#切回主窗口
driver.switch_to.window(curren_handle);
driver.find_element_by_css_selector(".names").send_keys('admin1');
driver.find_element_by_partial_link_text('登录注册页面').click();
#再次调用函数
handless();
driver.find_element_by_css_selector('#username').send_keys('我是第三个窗口的')
sleep(3)
driver.quit();十七、  截屏
如果自动化测试脚本运行时出现了异常,选择截屏保存当时的信息
因为自动化脚本是由程序去执行的,因此有时候打印的错误信息并不十分明确,如果在执行出错的时候
对当前窗口截图保存,那么通过图片就可以非常直观地看到出错的原因方法:
driver.get_screenshot_as_file(imgpath)imgpath:图片保存路径实例:
import time;
from selenium import webdriver;
from time import sleep;driver=webdriver.Chrome();
url='F:/python/hmtlfile/windows.html';
driver.get(url);
driver.maximize_window();
"""
需求:
1、在页面输入用户名
2、截屏保存在当前路径下(扩展:保存到上一级的image目录下、使用时间戳来动态保存图片)
"""
driver.find_element_by_css_selector('.names').send_keys('admin');
#driver.get_screenshot_as_file('./jiepin.png');
#driver.get_screenshot_as_file('../image/jiepin.png');
driver.get_screenshot_as_file('../image/%s.png'%(time.strftime('%Y_%m_%d %H_%M_%S')));#想要使用time,要先导入time包。ctrl+alt+空格导包。
#strftime是将时间转为字符串
sleep(3);
driver.quit();十八、验证码处理
验证码是一种随机生成的信息(数字、字母、汉字、图片、算术题等)为了防止恶意的请求行为,增加应用的安全性处理方式:Selenium中并没有对验证码处理的方法,只能根据项目情况使用以下方式
1、去掉验证码(仅能够在测试环境下使用)
2、设置万能验证码(生产环境和测试环境使用):例如在代码中加入生成的验证码后面加一句“or  888888"之类的,设置一下复杂一点的验证码并且在脚本中提交的一直是这个验证码
3、验证码识别技术(通过python-tesseract来识别图片类型验证码,但成功率很低)
4、记录cookie(通过记录cookie进行跳过登录 :这是最靠谱的一种办法,项目中建议使用这种方法十九、Cookie
1、说明:
Cookie是由Web服务器生成,并且保存在用户浏览器上的小文本文件,它可以包含用户相关的信息。
数据格式:键值对组成
产生:客户端请求服务器,如果服务器需要记录该用户状态,就向客户端浏览器颁发一个Cookie数据
使用:当浏览器再次请求该网站时,浏览器把请求的数据和Cookie数据一同提交给服务器,服务器检查 该
Cookie,以此来辨认用户状态2、应用场景:3、Selenium操作cookie
1)get_cookie(name)           --->获取指定cookie        括号里的name是cookie的名称
2)get_cookies()                  ---->获取本网站所有本地cookies
3)add_cookie(cookie_dict)   ---->添加cookie       cookie_dict:一个字典对象,必选的键包括:“name" and "value"3.1 案例:
需求:使用cookie实现跳过登录
1)手动登录百度,获取cookie
2)使用获取到的cookie,达到登录目的,然后就可以执行登录之后的操作import time;
from selenium import webdriver;
from time import sleep;
driver=webdriver.Chrome();
driver.maximize_window();
url='https://www.baidu.com';
driver.get(url);
driver.add_cookie({'name':'BDUSS','value':'g1a2J2N35RNENxakRQQnpiY3N1WlExNXk3WWtnNFNTcDlLSHNyYXVneTZWTnhlRVFBQUFBJCQAAAAAAAAAAAEAAACwstAKc2h1aXFpbmdmdQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALrHtF66x7ReUW'})
#上面这个value值,是去firefox浏览器复制方便一点,步骤:1、打开百度,点击登录,在输入用户名密码后先清空所有cookie,然后点击【登录】按钮,然后
# 在“网络--->域名为www.baidu.com,类型为html的person文件里,找到Cookie名字为BDUSS后面的一长串内容,复制过来就行了
"""
需求:
使用cookie绕过百度登录
步骤:
1、手动登录百度网站
2、手动获取登录后的cookies 'BDUSS'
3、使用selenium内的add_cookie({'name':'BDUSS','value':'根据实际填写'})           #这个BDUSS是百度的,其他网站的不是这样
"""
sleep(3);
#需要刷新才能看到效果
driver.refresh();
sleep(5);
driver.quit();扩展:
可以先使用这种方法来获取上面那一长串的value
cookie=driver.get_cookie('BDUSS');
print('cookie:',cookie)另外:获取所有的cookie信息:
cookies=driver.get_cookies()二十、UnitTest框架
framework:框架、为解决一类事情的功能集合
UnitTest框架:是python自带的一个单元测试框架,用它来做单元测试。
为什么使用UnitTest框架:
1、能够组织多个用例去执行
2、提供丰富的断言方法
3、能够生成测试报告UnitTest核心要素
1、TestCase       测试用例
2、TestSuite    套件(批量用例)
3、TestRunner    运行(以文本形式 text TestRunner)
4、TestLoader    运行
5、Fixture    (工厂装置)两个函数,前置、后置必运行函数1、TestCase  测试用例详解:案例:定义一个实现加法操作的函数,并对该函数进行测试定义测试用例:
1)、导包:import unittest
2)、定义测试类:新建测试类必须继承unittest.TestCase
3)、定义测试方法:测试方法名称必须以test开头执行测试用例:
方式一:使用pycharm在代码上点击鼠标右键,选择使用UnitTest运行
方式二:调用unittest.main()来运行实例:
import unittest;
"""
需求:
定义一个实现加法\减法操作的函数,并对该函数进行测试
步骤:
1)、导包:import unittest
2)、定义测试类:新建测试类必须继承unittest.TestCase
3)、定义测试方法:测试方法名称必须以test开头
"""
#编写求和函数
def add(x,y):return x+y;
#编写减法函数
def sub(x,y):return x-y;#定义测试类并继承
class Test01(unittest.TestCase):#定义测试方法  注意:以test字母开头def test_add(self):#调用 要用的函数result=add(1,1)print('结果为:',result);#定义第二个测试方法:def test_sub(self):           #假设光标定在这里或上面的test_add方法后面,运行unittest,运行结果 那里是显示Test passed:1。# 如果想运行多个用例,则需要把光标定在classrg dmresult=sub(10,5)print('结果为:',result);运行结果为:
Ran 2 tests in 0.003sOK
结果为: 2
结果为: 52、TestSuite  测试套件:
说明:多条用例集合在一起,就是一个TestSuite
使用:
1、实例化:suite=unittest.TestSuite()            #suite为TestSuite实例化的名称
2、添加用例:suite.addTest(ClassName("MethodName"))         #添加的用例是另外一个py文件写好的UniteTest文件里的类名和方法名
3、添加扩展:suite.addTest(unittest.makeSuite(ClassName))    #搜索指定ClassName内以test开头的方法并添加到测试套件中实例:
"""
目标:UnitTest框架      ---TestSuite使用步骤:
1)、导包:import unittest
2)、实例化获取 TestSuite对象
3)、调用addTest() 方法添加用例到指定套件中
"""
#导包:import unittest
import unittest;
from UnitTest.UnitTest_01 import Test01;
#实例化获取 TestSuite对象
suite=unittest.TestSuite()
#调用addTest 方法添加用例到指定套件中
#写法1:类名(”方法名“)
suite.addTest(Test01("test_add"));
suite.addTest(Test01("test_sub"));#扩展  写法2 添加测试类中所有test开头的方法
suite.addTest(unittest.makeSuite(Test01));#执行测试套件
runner=unittest.TextTestRunner();
runner.run(suite);3、TextTestRunner是用来执行测试用例和测试套件的          执行后会有文本显示通过或没通过
使用:
1、先导包
2、实例化:runner=unittest.TextTestRunner();
3、执行:runner.run(suite)   #suite为测试套件名称4、TestLoader 类
说明:用来加载TestCase到TestSuite中,即加载满足条件的油荒用例(默认是以test开头的方法,这里可以按实际情况设置以什么开头),并把测试用例封装成测试套件。使用unittest.TestLoader,通过该类下面的discover()方法自动搜索指定目录下指定开头的.py文件,并将查找到的测试用例组装到测试套件;
用法:suite=unittest.TestLoader().discover(test_dir,pattern='test*.py')test_dir :指定的测试用例目录pattern:为查找的.py文件的格式,默认为'test*.py'也可以使用unittest.defaultTestLoader 代替 unittest.TestLoader();
运行:实例:
假设在UnitTest文件夹写UnitTest_Run_testloader.py文件来运行case文件夹下面的用例们,执行其中所有以test开头的.py文件里的用例
"""
目标:使用TestLoader()类
作用:搜索指定目录下指定开头的.py文件,在py文件中搜索test开头的测试方法,并将这些方法添加到测试套件中
需求:运行case目录下test01.py至test05.py文件步骤:
1)、导包:import unittest
2)、调用方法
3)、执行 套件
"""
#导包:import unittest
import unittest;
#调用方法
#写法一
suite=unittest.TestLoader().discover("../case",pattern='test*.py');#如果不需要指定文件以什么开头,执行case目录下所有模块,则不需要pattern参数
#写法二、扩展,使用defaultTestLoader,不需要括号,推荐使用:
#suite=unittest.defaultTestLoader.discover('../case');         #直接调用case目录下所有模块文件
#执行测试套件
unittest.TextTestRunner().run(suite);以上实例,假设case目录下的文件列表是这样子的:
test01.py
test02.py
test03.py
test04.py
test05.py
aaaaa.py则根据pattern='test*.py'来筛选,以a开头的最后一个文件是不会被添加到测试套件中的,仅执行前5个文件,如果不加pattern参数,则第六个也执行TestLoader与TestSuite的区别(它们都是测试套件,只是实现方式不同)
1、TestSuite需要手动添加测试用例(可以添加测试类,也可以添加测试类中的某个测试方法)
2、TestLoader是搜索指定目录下的指定开头的.py文件,并添加测试类中的所有以test开头的测试方法到测试套件中,不能指定添加测试方法;工作中建议使用TestLoader5、Fixture:是一个概述,对一个测试用例环境的初始化和销毁就是一个Fixture
控制级别:
1)函数级别(实例1)       setUp(self)  每一个方法之前都运行一次,执函数执行之后就会执行一次tearDown()
2)类级别(实例2)       setUpClass 只在类之前运行一次,比如执行十个用例,只打开一次浏览器和最大化浏览器和设置隐式等待,如果用函数级别的就会特别烦注意:类方法必须使用@classmethod修饰
3)模块级别(仅作了解,项目中很少用到):setUpModule()\tearDownModule()提示:无论使用函数级别还是类级别,最常用的场景就是:初始化:1、获取浏览器实例化对象2、最大化浏览器3、设置隐式等待结束:关闭浏览器驱动实例1"""
目标:unittest 中的fixture用法fixture其实就是两个函数,这2个函数可以一起使用也可以单独使用1、初始化函数:def setUp()2、结束函数:def tearDown()需求:每个方法之前都要运行一次setUp,之后都要运行一次tearDown
"""
#导包:import unittest
import unittest;
class Test03(unittest.TestCase):    #需要继承,写在括号里def setUp(self):print("setUp被执行");def tearDown(self):print("tearDown被执行")def test01(self):print("test01被执行")def test02(self):print("test02被执行")结果是:
setUp被执行
test01被执行
tearDown被执行
setUp被执行
test02被执行
tearDown被执行实例2"""
目标:unittest 中的fixture用法fixture其实就是两个函数,这2个函数可以一起使用也可以单独使用1、初始化函数:def setUp()2、结束函数:def tearDown()需求:每个方法之前都要运行一次setUp,之后都要运行一次tearDown
"""
#导包:import unittest
import unittest;
class Test03(unittest.TestCase):    #需要继承,写在括号里@classmethoddef setUpClass(cls):          #执行类方法,需要使用@classmethod来修饰,否则报错print("setUpClass被执行");@classmethoddef tearDownClass(cls):print("tearDownClass被执行");def setUp(self):print("setUp被执行");def tearDown(self):print("tearDown被执行")def test01(self):print("test01被执行")def test02(self):print("test02被执行")结果是:
setUpClass被执行
setUp被执行
test01被执行
tearDown被执行
setUp被执行
test02被执行
tearDown被执行
tearDownClass被执行二十一、断言     assert
让程序代替人为判断测试程序执行结果 是否符合预期结果的过程自动化脚本在执行的时候一般是无人值守状态,我们不知道执行结果是否符合预期结果,所以我们需要让程序
代替人为检测程序执行的结果是否符合预期结果。这就需要使用断言。UnitTest断言方法:(常用的)
1、assertTrue(expr,msg=None)    验证expr是true,如果是false,则fail
2、assertFalse(expr,msg=None)    验证expr是false,如果是true,则fail
3、assertEqual(expected,actual,msg=None)    验证expected==actual,不等则fail(比较重要,需要掌握)
4、assertNotEqual(first,second,msg=None)    验证first!=second,相等则fail
5、assertIsNone(obj,msg=None)    验证obj是None,不是则fail
6、assertIsNotNone(obj,msg=None)    验证obj不是None,是则fail
7、assertIn(member,container,msg=None)    验证是否member in container(需要掌握)
8、assertNotIn(member,container,msg=None)    验证是否member not in container实例:
"""
目标:unittest 中的常用断言1、assertTrue:如果结果为True通过,否则失败"""
import unittest;
def add(x,y):return x+y;class Test03(unittest.TestCase):    #需要继承,写在括号里def test01(self):result=add(4,4);flat=result>=8;self.assertTrue(flat);self.assertEqual("wq","wq");#应用场景,登录成功后,获取用户名称看是否等于预期的名称#判断后面的字符串是否包含前面的字符串self.assertIn('hello','helloword');#判断是否为Noneflag=None;self.assertIsNone(flag);实例2"""
需求:登录百度1、输入:输入正确的用户名和不输入密码就点击登录2、断言:提示信息为“请您输入密码”3、要求:如果断言出错,截屏保存"""
import unittest;
from selenium import webdriver;
from time import sleep;
import time;#定义测试类 并继承 unittest.TestCase
class TestBaiduLogin(unittest.TestCase):#定义初始化方法def setUp(self):#获取浏览器驱动并打开url并最大化浏览器和设置隐式等待self.driver=webdriver.Chrome();url="https://baidu.com"self.driver.get(url);self.driver.maximize_window();self.driver.implicitly_wait(30);#定义结束方法def tearDown(self):sleep(3);self.driver.quit();#关闭浏览器驱动#定义登录测试方法  密码输入错误def test_login_error_psw(self):driver=self.driver;# 点击登录连接driver.find_element_by_css_selector(".s-top-login-btn").click();driver.find_element_by_css_selector('.tang-pass-footerBarULogin').click();#输入用户名driver.find_element_by_css_selector('.pass-text-input-userName').send_keys('shuiqingfu')#输入密码driver.find_element_by_css_selector('.pass-text-input-password').send_keys('');#点击登录driver.find_element_by_css_selector('.pass-button-submit').click();sleep(3)#获取登录后提示信息result=driver.find_element_by_css_selector(".pass-generalError-error").text;print('提示信息:',result);#定义预期结果expect_result='请您输入密码2';try:#断言self.assertEqual(result,expect_result)except AssertionError:# 截图   使用时间戳来动态生成图片名称,不会重复driver.get_screenshot_as_file("../image/{}.png".format(time.strftime("%Y_%m_%d %H_%M_%S")));#抛出异常raise运行结果:
Tests failef :1提示信息: 请您输入密码Ran 1 test in 22.700sFAILED (errors=1)Error
Traceback (most recent call last):File "C:\Program Files\JetBrains\PyCharm Community Edition 2019.3.4\plugins\python-ce\helpers\pycharm\teamcity\diff_tools.py", line 32, in _patched_equalsold(self, first, second, msg)File "C:\Users\wushuirong\AppData\Local\Programs\Python\Python35\lib\unittest\case.py", line 817, in assertEqualassertion_func(first, second, msg=msg)File "C:\Users\wushuirong\AppData\Local\Programs\Python\Python35\lib\unittest\case.py", line 1190, in assertMultiLineEqualself.fail(self._formatMessage(msg, standardMsg))File "C:\Users\wushuirong\AppData\Local\Programs\Python\Python35\lib\unittest\case.py", line 662, in failraise self.failureException(msg)
AssertionError: '请您输入密码' != '请您输入密码2'
- 请您输入密码
+ 请您输入密码2
?       +During handling of the above exception, another exception occurred:Traceback (most recent call last):File "F:\python\UnitTest\UnitTest_Run_assert断言实例.py", line 51, in test_login_error_pswself.assertEqual(result,expect_result)File "C:\Program Files\JetBrains\PyCharm Community Edition 2019.3.4\plugins\python-ce\helpers\pycharm\teamcity\diff_tools.py", line 38, in _patched_equalsraise error
teamcity.diff_tools.EqualsAssertionError:  :: 请您输入密码 != 请您输入密码2扩展:
"""
目标:python自带的断言"""
#判断2个字符串是否相等
# assert 'hello'=='hello';
#assert 'hello'=='hallo';  #错误类型:AssertionError
#第二个字符串是否包含第一个字符串
# assert 'h' in 'hello';
# assert 'ha' in 'hello';
#判断是否为True\False       1/0
# assert True;
# assert False;二十二、参数化
根据需求动态获取参数并引用的过程
应用场景:解决相同业务逻辑,不同测试数据的问题
如何实现:
需要安装unittest扩展插件parameterized来实现
File-->Settings-->Project:python-->Project Interpreter--->点击+:输入parameterized---->Install Package来进行安装
安装完之后在cmd里面输入pip list可以找到import unittest
from parameterized import parameterized;
"""
目标:parameter插件应用
步骤:
1、导包   from parameterized import parameterized;
2、修饰测试函数   @parameterized.expand(列表类型数据)
3、在测试函数中使用变量接收,传递过来的值语法:1、单个参数:值为列表2、多个参数:值为列表嵌套元组  如:[(1,2,3),(2,3,4)]"""class Test01(unittest.TestCase):#单个参数# @parameterized.expand(["1","2","3"])# def test_add_one(self,num):#     print("num:",num)#多个参数  写法一:一般调试的时候才这样子写,实际项目中,数据是分离出去的# data=[(1,2,3),(2,3,5)]# @parameterized.expand(data)# def test_add_more(self,a,b,result):#     print('{}+{}={}:'.format(a,b,result))#多个参数  写法二:实际工作中用这种#先定义一个获取数据的函数def get_data():return [(1,2,3),(3,3,6)]@parameterized.expand(get_data())def test_add_more2(self,a,b,result):print("{}+{}={}:".format(a,b,result));实例:
import unittest
from parameterized import parameterized;
""""""
def add(x,y):return x+y;
def get_data():return [(1,2,3),(3,3,5)]       #这里的5改成6,则会通过测试,这里3+3=5则会提示出错
class Test01(unittest.TestCase):@parameterized.expand(get_data())def test_add_more2(self,a,b,expect):result=add(a,b);assert result==expect;二十三、UnitTest的跳过
对于一些未完成的或者不满足测试条件的测试函数和测试类,可以跳过执行
使用方法:
#直接将测试函数标记成跳过
@unittest.skip('代码未完成')
场景:一般适合功能未完成用例
#根据条件判断测试函数是否跳过
@unitest.skipIf(condition,reason)
场景:一般判断条件满足就不执行,如:达到指定版本,此功能失效
实例:
import unittest
version=20;         #这个数字如果大于25就会跳过,小于25就会执行test03
class Test01(unittest.TestCase):@unittest.skip("此方法功能暂未完成")def test01(self):"""此方法功能暂未完成"""def test02(self):print('test02');@unittest.skipIf(version>25,"大于25,跳过")def test03(self):print("test03");二十四、html报告
1、首先去下载一个插件
HTMLTestRunner下载HTMLTestRunner下载地址: http://tungwaiyip.info/software/HTMLTestRunner.html
2、HTMLTestRunner修改因为这个模块原本给python2.0用的,我用的python是3.x,所以下载后需要做些修改。下载后修改:(Ctrl+G可以跳转到指定行)94行引入的名称要改,从 import StringIO 改成import io。539行 self.outputBuffer = StringIO.StringIO() 要改成self.outputBuffer=io.StringIO()631print >>sys.stderr, ‘\nTime Elapsed: %s’ % (self.stopTime-self.startTime)修改为:print (sys.stderr, ‘\nTime Elapsed: %s’ %(self.stopTime-self.startTime))642行,if not rmap.has_key(cls): 需要换成 if not cls in rmap:766行的uo = o.decode(‘latin-1),改成 uo=o772行,把 ue = e.decode(‘latin-1) 直接改成 ue = e
————————————————3、HTMLTestRunner存放路径修改好的模块存放在…\python\tools下4、把用例放在case文件夹下
5、建一个report文件夹存放报告
6、建立执行代码的文件:
import unittest
import time
from tools.HTMLTestRunner import HTMLTestRunner;
"""
基于unittest框架执行生成hmtl报告
操作:
1、复制HtmlTestRunner.py文件到指定目录
2、导包
3、获取报告存放文件流,并实例化HTMLTestRunner类,执行run方法"""
#定义测试套件
suite=unittest.defaultTestLoader.discover('../case',pattern='test*.py');
#定义报告存放路径及文件名称
report_dir='../report/{}.html'.format(time.strftime("%Y_%m_%d %H_%M_%S"))
#获取报告文件流 并执行
with open(report_dir,'wb') as f:HTMLTestRunner(stream=f,verbosity=2,title='XX项目自动化测试报告',description='操作系统 win10').run(suite);7、运行后在report里就有报告了二十五、PO实践
PO:page(页面)  object(对象)
v1:不采用任何模式(线性模型)
v2:unittest
v3:业务代码和页面对象分离:
v4:实际项目中的PO模式编写:测试用例(使用TPShop项目的登录页):
1、账号不存在进入登录页面输入一个不存在的用户名输入密码输入验证码点击登录按钮获取错误提示信息2、密码错误进入登录页面输入用户名输入一个错误的密码输入验证码点击登录按钮获取错误提示信息V1实例:#导包
from selenium import webdriver;
import time#获取driver对象
driver=webdriver.Chrome()#最大化浏览器
driver.maximize_window();#隐式等待
driver.implicitly_wait(3);#打开url
url='http://localhost/index.php/Admin/Admin/login.html'
driver.get(url)# 输入不存在的用户名
driver.find_element_by_name('username').send_keys('wushuirong');#输入密码
driver.find_element_by_name('password').send_keys('123456')#输入验证码
driver.find_element_by_css_selector('#vertify').send_keys('123456')
driver.find_element_by_name('submit').click();#获取登录后的错误提示信息
tips=driver.find_element_by_css_selector('.error').text;
print('提示信息是:',tips);
expect='用户名不存在';
try:assert tips==expect;
except AssertionError:driver.get_screenshot_as_file('../image/{}.png'.format(time.strftime("%Y_%m_%d %H_%M_%S")));V2实例:
#导包
import unittest;
import time;
from selenium import webdriver;
#新建测试类 并继承
class TestLogin(unittest.TestCase):driver=None;#初始化@classmethoddef setUpClass(cls):cls.driver=webdriver.Chrome();cls.driver.maximize_window();cls.driver.implicitly_wait(3);url='http://localhost/index.php/Admin/Admin/login.html'cls.driver.get(url);#结束@classmethoddef tearDownClass(cls):cls.driver.quit();#新建测试方法#用户名不存在def test_login_username_not_exist(self):# 输入不存在的用户名driver=self.driver;driver.find_element_by_name('username').send_keys('wushuirong');# 输入密码driver.find_element_by_name('password').send_keys('123456')# 输入验证码driver.find_element_by_css_selector('#vertify').send_keys('123456')   #因为没有改源代码,所以这个验证码是错的,下面的提示信息永远是验证码错误,暂时先这样driver.find_element_by_name('submit').click();# 获取登录后的错误提示信息tips = driver.find_element_by_css_selector('.error').text;print('提示信息是:', tips);expect = '用户名不存在';try:assert tips == expect;except AssertionError:driver.get_screenshot_as_file('../image/{}.png'.format(time.strftime("%Y_%m_%d %H_%M_%S")));time.sleep(3);def test_login_password_error(self):# 输入正确的用户名driver = self.driver;driver.find_element_by_name('username').clear();driver.find_element_by_name('username').send_keys('admin');# 输入错误的密码driver.find_element_by_name('password').send_keys('123456')# 输入验证码driver.find_element_by_css_selector('#vertify').send_keys('123456')  # 因为没有改源代码,所以这个验证码是错的,下面的提示信息永远是验证码错误,暂时先这样driver.find_element_by_name('submit').click();# 获取登录后的错误提示信息tips = driver.find_element_by_css_selector('.error').text;print('提示信息是:', tips);expect = '密码错误';try:assert tips == expect;except AssertionError:driver.get_screenshot_as_file('../image/{}.png'.format(time.strftime("%Y_%m_%d %H_%M_%S")));V3实例:页面层和业务层分离
首先在V3文件夹里再建两个文件夹page和scripts分别装页面层和业务层的代码,然后页面层的文件名称必须以page开头,业务层的文件名称以test开头
以下是page_login.py
"""
页面对象编写技巧
类名:使用大驼峰将模块名称抄进来,有下划线就去掉下划线
方法:根据业务需求,每个操作步骤单独封装一个方法方法名:page_xxx
"""
from selenium import webdriver;
class PageLogin:def __init__(self):self.driver = webdriver.Chrome();self.driver.maximize_window();self.driver.implicitly_wait(3);url = 'http://localhost/index.php/Admin/Admin/login.html'self.driver.get(url);# 页面层#输入用户名def page_input_username(self,username):self.driver.find_element_by_name('username').send_keys(username);#输入密码def page_input_password(self,pwd):self.driver.find_element_by_name('password').send_keys(pwd);#输入验证码def page_input_verify_code(self,code):self.driver.find_element_by_css_selector('#vertify').send_keys(code)#点击登录def page_input_submit(self):self.driver.find_element_by_name('submit').click();#获取异常提示信息def page_input_error(self,error):return self.driver.find_element_by_css_selector('.error').text;#业务层#组装登录业务方法,给业务层调用def page_login(self,username,pwd,code):self.page_input_username(username);self.page_input_password(pwd);self.page_input_verify_code(code);self.page_input_submit();以下是test_login.py:
# 导包
import unittest;
from v3.page.page_login import PageLogin;       #把页面层的模块和类导进来
import time;
from parameterized import parameterized;# 新建测试类
class TestLogin(unittest.TestCase):# 初始化方法def setUp(self):# 获取登录页面对象self.login = PageLogin();# 结束方法def tearDown(self):self.login.driver.quit();# 新建测试方法@parameterized.expand([('wushuirong','123456','8888','账号不存在'),('admin','123455','8888','密码错误')])def test_login(self, username,pwd,code,expect):#调用测试登录方法self.login.page_login(username,pwd,code)#获取登录后的提示信息msg=self.login.page_input_error(expect);#断言try:self.assertEqual(msg,expect)except AssertionError:self.driver.get_screenshot_as_file('../image/{}.png'.format(time.strftime("%Y_%m_%d %H_%M_%S")));运行结果是:
Tests failed:2
AssertionError: '验证码错误!' != '账号不存在'
- 验证码错误!
+ 账号不存在AssertionError: '验证码错误!' != '密码错误'
- 验证码错误!
+ 密码错误因为没有改过源代码,没有设置万能验证码,所以这里的验证码一直是错的,没办法验证登录名是否存在和密码错误,
实际项目中需要设置万能验证码,或者直接用cookies来跳过登录这一步,或者直接去掉验证码。V4实例    比V3多了基类,公共的方法适用于任何页面任何项目
建三个文件夹
base (基类):      存放page页面里一些公共的方法,给page用
例如:class Base:#初始化方法def __init__(self):pass#查找元素方法(暂时提供下面三个方法用)def base_find_element(self):pass#点击方法def base_click(self):pass#输入方法def base_input(self):pass#获取文件方法def base_get_text(self):pass#截图方法def base_get_image(self):pass注意:1、以上方法,解包只需要一次,在查找元素解包(详细看代码)2、driver为虚拟,谁调用base时,谁传入,无需关注从哪里来3、loc:真正使用loc的方法只有查找元素page(页面对象):一个页面封装成一个对象应用:继承base;(不用导包的方式)实现:1、模块名:page+实际操作模块名称        page_login.py2、页面对象名:以大驼峰的方法将模块名抄进来,有下划线就去掉下划线3、方法:涉及元素,将每个元素操作单独封装一个操作方法4、组装:根据需求组装以上操作步骤。例如:
class PageLogin():#输入用户名def page_input_username(self):pass#输入密码def page_input_password(self):pass#输入验证码def page_input_verity_code(self):pass#点击【登录】def page_click_login_btn(self):pass#获取登录异常信息def page_get_err_info(self):pass#截图def page_get_screenshot(self):pass#组合业务方法def page_login(self):pass然后还有一件事情就是页面配置数据,例如登录用户名、密码、验证码等信息,需要另外起一个文件存放,把一个项目里所有类似的信息存放在同一个文件里比较方便管理
就是page文件夹下面建一个__init__.py文件,即利用文件包(文件包比文件夹多一个init文件)的机制,在同一个page文件里的文件可以通过文件夹名.来获取__init__文件下的变量
实际操作看下面的“page文件夹里的详情”:scripts(业务层):导包调用page页面实现:1、模块:test+实际操作模块名称   test_login.py2、测试业务名称:以大驼峰方法将模块名抄进来,有下划线就去掉下划线。TestLogin3、方法:1)初始化方法setUp()   注:在unittest框架中,不能使用def __init__()初始化方法#实例化页面对象#前置操作   如:打开登录页2)结束方法 tearDown()#关闭浏览器驱动3)测试方法#根据要操作的业务来实现base.py详细代码:
from selenium.webdriver.support.wait import WebDriverWait
import time;class Base:#初始化方法def __init__(self):# self.driver=driver;#临时代替driverself.driver=webdriver.Chrome();self.driver.maximize_window();self.driver.get("http://localhost/index.php/Admin/Admin/login.html");#查找元素方法(暂时提供下面三个方法用)def base_find_element(self,loc,timeout=30,poll=0.5):  #设置后面两个参数的目的是为了有些场景的等待时间可能 会是2秒或其他时长,如果不传参就默认30秒,如果传参就按实际参数来等待#使用显式等待找到一个元素return WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll).until(lambda x:x.find_element(*loc)); #loc是位置#点击方法def base_click(self,loc):self.base_find_element(loc).click();#输入方法def base_input(self,loc,value):el=self.base_find_element(loc);el.clear();el.send_keys(value);#获取文件方法def base_get_text(self,loc):return self.base_find_element(loc).text;#截图方法def base_get_image(self):self.driver.get_screenshot_as_file('../image/{}.png'.format(time.strftime("%Y_%m_%d %H_%M_%S")));page文件夹里的详情:
1、__init__.py的详细代码:
from selenium.webdriver.common.by import By;
"""以下为登录页面元素的配置信息"""
#用户名
login_username=By.NAME,'username';#密码
login_pwd=By.NAME,'password'
#验证码
login_verify_code=By.CSS_SELECTOR,'#vertify';
#登录按钮
login_btn=By.NAME,'submit';
#获取登录后的错误提示信息
login_err_info=By.CSS_SELECTOR,'.error';"""以下为订单页面元素的配置信息"""
#暂时没有page_login.py文件详细代码:
from v4 import page;   #在这里包入page包,就可以直接page.    点了之后就会出现刚才在init文件里写的全部变量
from v4.base.base import Baseclass PageLogin(Base):   #继续Base的方法,在这里输入后按ctrl+alt+空格导包#输入用户名def page_input_username(self,username):self.base_input(page.login_username,username);    #这一行代码,首先self.后显示在base里设置的“输入方法  base_input",选择后#再在括号里输入loc,即页面元素,在init文件里设置的“用户名  login_username",#这里输入page.之后就会跳出来可以选择该变量;最后的username是参数,需要在外面存#放的txt等文件里准备好测试数据,再传进来#输入密码def page_input_password(self,pwd):self.base_input(page.login_pwd,pwd)#输入验证码def page_input_verity_code(self,code):self.base_input(page.login_verify_code,code)#点击【登录】def page_click_login_btn(self):self.base_click(page.login_btn);#获取登录异常信息def page_get_err_info(self):return self.base_get_text(page.login_err_info); #获取一定要返回#截图def page_get_screenshot(self):self.base_get_image();#组合业务方法def page_login(self,username,pwd,code):self.page_input_username(username);self.page_input_password(pwd);self.page_input_verity_code(code);self.page_click_login_btn();scripts文件夹下的test_login.py 详细代码:#导包
import unittest;from parameterized import parameterizedfrom v4.page.page_login import PageLogin;
def get_data():return [('wushuirong','123456','8888','账号不存在'),('admin','123455','8888','密码错误')];
#新建测试类并继承
class TestLogin(unittest.TestCase):#setUpdef setUp(self):#实例化 获取页面对像PageLoginself.login=PageLogin();#tearDowndef tearDown(self):self.login.driver.quit();#登录测试方法@parameterized.expand(get_data())def test_login(self,username,pwd,code,expect_result):#调用登录方法self.login.page_login(username,pwd,code);#获取登录提示信息msg=self.login.page_get_err_info();try:#断言self.assertEqual(msg,expect_result);except AssertionError:self.login.page_get_screenshot();raise;           #加上这句话,会使得如果断言有错就会抛异常,同时截图。如果#不加上这句话,只会截图,用例还是会passPS:断言出错时截图,同时抛异常,用例不是pass:加上raise最后,在这个方法的类处定点光标,然后运行,即可以进行完整的测试。二十六、数据驱动(重中之重)
以数据来驱动整个测试用例的执行,也就是测试数据决定测试结果
比如测试加法,测试数据是11,那结果就是2,如果测试数据是12,测试结果就是3特点:自动化脚本写完之后基本不会再动,维护的重点在测试数据上,实现它要依赖于参数化的技术传入数据的方式(测试数据的来源)
1)直接定义在测试脚本中(简单直观,但代码和数据未实现真正的分离,不方便后期维护)
2)从文件读取数据,如JSON、excel、xml、txt等格式文件
3)从数据库中读取数据
4)直接调用接口获取数据源
5)本地封装一些生成数据的方法1、JSON
是JS对象表示法,基本文本,独立于语言的轻量级数据交换格式语法规则:
- 大括号保存对象
- 中括号保存数组
- 对象数组可以互相嵌套
- 数据采用键值对表示
- 多个数据由逗号分隔JSON值
- 数字(整数或浮点数)
- 字符串(在双引号中)
- 逻辑值(true 或 false)
- 数组
- 对象
- null数据操作:
1、首先要导入依赖包
import json
2、python字典与JSON之间的转换
a) 把python字典类型转换为JSON字符串
实例:
"""
目标: 把python字典类型转换为JSON字符串
案例:data={"name":"张三","age":18}
操作:
1、导包
2、调用dumps()方法 将字典转换成json字符串
注意:json中还有一个方法dump()  写入json  不要写错"""
#导包
import json
#定义字典
data={"name":"张三","age":18}
#调用dumps()方法 将字典转换成json字符串
print("转换之前的数据类型:",type(data))
d2=json.dumps(data);
print("转换之后的数据类型:",type(data))
print(d2);结果是:
转换之前的数据类型:
转换之后的数据类型:
{"name": "\u5f20\u4e09", "age": 18}b)将json转换成Python字典
"""将字符串转换成字典"""
#定义字符串
data='{"name":"张三","age":18}';
print("转换之前的数据类型:", type(data))
d3=json.loads(data);
print("转换之后的数据类型:", type(d3))
print(data);结果:
转换之前的数据类型:
转换之后的数据类型:
{"name":"张三","age":18}注意:
错误写法:data="{'name':'张三'}"
这样子写会报错,说属性名必须用双引号,因此一定要用单引号包双引号来写
3、JSON文件读写
a)读取json文件
with open('data.json',encoding='UTF-8') as f:data=json.load(f); #返回的数据类型为字典或列表
实例:读取的是下面例子写入的json文件
"""
目标: 读取road
案例:
之前写入的文件
data={"name":"tom","age":18}
"""
#导包
import json
#打开要读取的文件流 并调用load方法
with open("./data/write2.json",encoding="utf-8") as f:data=json.load(f);print(data);b)写入JSON文件
param={'name':'tom', 'age':20}
with open('data2.json', 'w', encoding='UTF-8') as f:json.dump(param,f);   #写什么东西,往哪写  f就是上面那个文件流"""
目标: 写入json
案例:
1、data={"name":"tom","age":18}
2、data={"name":"张三","age":18}
操作:
1、导包
2、调用dump()方法"""
#导包
import json
#定义字典
data={"name":"tom","age":18}
data2={"name":"张三","age":18}
#获取文件流 并写入数据
with open("./data/write.json","w",encoding="utf-8") as f:#调用dump()方法json.dump(data,f);
with open("./data/write2.json","w",encoding='utf-8') as f2:json.dump(data2,f2,ensure_ascii=False);   #这里如果没有加最后一个ensure_ascii=False,则write2文件里的中文会以阿斯卡玛的方式显示结果是在data文件夹里生成两个文件write.json和write2.json,内容分别是:{"age": 18, "name": "tom"}{"age": 18, "name": "张三"}综合实例一:网页计算器安全
1、采用po模式 的分层思想对页面进行封装
2、编写测试脚本
3、使用参数化传入测试数据
PS:input的值不是获取text,而是获取其value属性的值分析:
结构:base#初始化方法#查找元素#点击#获取value属性方法封装#截图page#点击数字for n in str(num):loc=By.ID,"simple{}".format(n);#调用base内的方法#点击加号#点击等号#获取结果#组装业务方法scripts#初始化方法#获取计算页面页面对象#获取driver#结果方法#关闭driver#调用测试方法#调用加法运算业务方法#断言#截图driver封装类名:#定义类变量driver=None;#获取driver方法@classmethoddef get_driver(cls):if cls.driver is None:#实例化浏览器#最大化#打开浏览器cls.driver.get(page.url);return cls.driver;#退出driver@classmethoddef quit_driver(cls):if cls.driver:cls.driver.quit();#注意:此处一定要置空cls.driver=None;读取json数据封装
1、读取工具封装#导包#打开json获取文件流  并调用load方法
2、组装读取出来的数据格式封装#预期格式:[(),()]#默认实际格式{"":"","":""}思路:1、新建空列表2、使用字典.values()方法获取所有的字典值;3、使用列表.append((字典.get("键名"))4、返回列表arrs
项目实际:
文件夹与文件层级:
网页计算器实例:base:base.pyget_driver.pydata:calc.jsonimage:page:__init__.pypage_calc.pyscripts:test_calc.pytool:read_json.py整体思路:
1、首先建好文件夹和文件名后,先写base文件里的基础方法
2、封装好get_driver
3、page文件里先把所有用例涉及的元素写好配置信息,在__init__.py文件里
4、page_calc.py写好全部操作的方法
5、tool里写好read_json.py的读取json文件的方法,以便在写test_calc.py的时候直接调用
6、写test_calc.py文件
7、准备测试用例数据具体源码:
base.py:
import time;
from selenium.webdriver.support.wait import WebDriverWait
class Base:#初始化方法def __init__(self,driver):self.driver=driver;#查找元素def base_find_element(self,loc,timeout=30,poll=0.5):"""          #输入三对双引号后按一下回车键就会显示该方法下的所有参数:param loc::param timeout::param poll::return:"""return WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll).until(lambda x:x.find_element(*loc));#点击def base_click(self,loc):self.base_find_element(loc).click();#获取value属性方法封装def base_get_vlaue(self,loc):return self.base_find_element(loc).get_attribute('value');#截图def base_get_image(self):self.driver.get_screenshot_as_file('../image/{}.png'.format(time.strftime("%Y_%m_%d %H_%M_%S")));get_driver.py:
from selenium import webdriver;
from 网页计算器实例 import page;
class GetDriver:#设置类属性driver=None;#获取driver@classmethoddef get_driver(cls):if cls.driver is None:#实例化浏览器cls.driver=webdriver.Chrome();#最大化cls.driver.maximize_window();#打开浏览器cls.driver.get(page.url);return cls.driver;#退出driver@classmethoddef quit_driver(cls):if cls.driver:cls.driver.quit();#注意:此处有一个大坑,关闭后driver不置空,跑多条用例是跑不起来了,因为上面判断了if cls.driver is None,所以要加下面这句cls.driver=None;__init__.py
"""以下为计算器配置数据"""
from selenium.webdriver.common.by import By
#由于数字键有一定的规律,所以暂时不用定位此键,用到的时候再考虑此键怎么解决
# calc_num=By.CSS_SELECTOR,"simple9";
#加号
calc_add=By.CSS_SELECTOR,"#simpleAdd";
#=号
calc_eq=By.CSS_SELECTOR,'#simpleEqual';
#获取结果
calc_result=By.CSS_SELECTOR,'#resultIpt';
#清屏
calc_clear=By.CSS_SELECTOR,'#simpleClearAllBtn';"""以下为服务器域名配置地址"""
url="http://cal.apple886.com/"page_calc.py:
from selenium.webdriver.common.by import By
from 网页计算器实例.base.base import Base;
from 网页计算器实例 import page;
class PageCalc(Base):#点击数字方法def page_click_num(self,num):for n in str(num):loc=By.ID,"simple{}".format(n);self.base_click(loc);#点击加号def page_click_add(self):self.base_click(page.calc_add)#点击=号def page_click_eq(self):self.base_click(page.calc_eq);#获取结果方法def page_get_value(self):return self.base_get_vlaue(page.calc_result);#点击清屏def page_click_clear(self):self.base_click(page.calc_clear);#截图def page_get_image(self):self.base_get_image();#组装加法运算方法def page_add(self,a,b):self.page_click_num(a);self.page_click_add();self.page_click_num(b);self.page_click_eq();test_calc.py:
import unittest;
from parameterized import parameterized;
import time;
from 网页计算器实例.base.get_driver import GetDriver
from 网页计算器实例.page.page_calc import PageCalc
from 网页计算器实例.tool.read_json import read_json
def get_data():datas=read_json('calc.json');#新建空列表arrs=[]for data in datas.values():arrs.append((data['a'],data['b'],data['expect']));return arrs;
class TestCalc(unittest.TestCase):driver=None;#setUpClass@classmethoddef setUpClass(cls):#获取drivercls.driver=GetDriver().get_driver();#初始化页面对象cls.calc=PageCalc(cls.driver);#tearDown@classmethoddef tearDownClass(cls):GetDriver().quit_driver();#测试方法 加法@parameterized.expand(get_data())def test_add_calc(self,a,b,expect):#调用加法运算业务方法self.calc.page_add(a,b);time.sleep(3)try:#断言self.assertEqual(self.calc.page_get_value(),str(expect)); #这里如果不加str会断言出错“3”!=3#截图except:self.calc.page_get_image();raise;read_json.py:
#导包
import json;
#调用load方法
def read_json(filename):filepath='../data/'+filename;with open(filepath,'r',encoding='utf-8') as f:return json.load(f);calc.json:
{
"calc_001":{"a": 1,"b": 2,"expect": 3},"calc_002":{"a": 1001,"b": 2,"expect":1002},"calc_003":{"a": 99,"b": 2,"expect": 101}
}以上测试用例数据,可以看到第二条的预期结果是故意写错的。因此最终运行结果是:
Tests failed:1,passed:2
002 != 1003Expected :1003
Actual   :1002      综合实例二:某网站的登录模块的单元测试实例
1.1 实现步骤
1、绽测试用例
2、采用PO模式的分层思想对页面进行封装
3、编写测试脚本
4、定义数据文件,实现参数化1.2 用例设计
ID       模块    优先级    测试标题             预置条件                    步骤描述        测试数据                                  预期结果              测试结果
login_001   登录    P0    用户名错误        1、打开首页        1、输入错误用户名    1、用户名:123        提示框提示:2、点击登录链接             2、输入密码    2、密码:123456        账号不存在3、输入验证码    3、验证码:万能验证码4、点击登录按钮
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
login_002   登录    P0    密码错误           1、打开首页        1、输入用户名    1、用户名:username             提示框提示:2、点击登录链接             2、输入错误密码    2、密码:123456        密码错误3、输入验证码    3、验证码:万能验证码4、点击登录按钮
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
login_003   登录    P0    用户名为空        1、打开首页        1、不输入用户名    1、用户名:        提示框提示:2、点击登录链接             2、输入密码    2、密码:123456        用户名不能为空3、输入验证码    3、验证码:万能验证码4、点击登录按钮
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
login_004   登录    P0    密码为空        1、打开首页        1、输入用户名    1、用户名:username            提示框提示:2、点击登录链接             2、不输入密码    2、密码:         密码不能为空3、输入验证码    3、验证码:万能验证码4、点击登录按钮
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
login_005   登录    P0    验证码为空        1、打开首页        1、输入用户名    1、用户名:username            提示框提示:2、点击登录链接             2、输入密码    2、密码:123456        验证码不能为空3、不输入验证码    3、验证码:万能验证码4、点击登录按钮
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------
login_006   登录    P0    正常登录           1、打开首页        1、输入用户名    1、用户名:username    登录成功2、点击登录链接             2、输入密码    2、密码:123456        3、输入验证码    3、验证码:万能验证码4、点击登录按钮-------------------------------------------------------------------------------------------------------------------------------------------------------------------------登录成功的标志:一般有"退出"这类的字眼查找元素判断是否操作成功  思路封装def base_if_success(self,loc):try:self.base_find_element(loc,timeout=2)#找到元素   assertTruereturn True;except:return False;如何区分正向逆向用例思路:在测试数据中添加一个标识正向用例或逆向用例的标记,如True/False步骤:1、调用登录方法(此登录方法中,只有输入用户名、输入密码、输入验证码、点击登录按钮)   不要封装点击登录连接2、判断是否正向用例:判断是否有”退出“点击”退出“点击登录连接地址否则:获取异常登录 信息断言操作如果异常提示是弹框,则需要关闭弹窗二十八、日志:
用于记录系统运行时的信息,对一个事件的记录;也称为Log
A:作用:
--调试程序
--了解系统程序运行的情况,是否正常
--系统程序运行故障分析与问题定位
--用来做用户行为分析和数据统计B:日志级别:优先级、重要性或严重程度
DEBUG      调试级别,打印非常详细的日志信息,通常用于对代码的调试
INFO         信息级别,打印一般的日志信息,突出强调程序的运行过程
WARNING 警告级别,打印警告日志信息,表明会出现潜在错误的情形,一般不影响软件的正常使用
ERROR      错误级别,打印错误异常信息,该级别的错误可能会导致系统的一些功能无法正常使用
CRITICAL   严重错误级别,一个严重的错误,这表明系统可能无法继续运行说明:一般建议只使用前四个级别
当为程序指定一个日志级别后,程序会记录所有日志级别大于或等于指定日志级别的日志信息,而不是仅仅记录指定级别的。C:日志的基本用法:
logging模块:python中有一个标准库模块logging可以直接记录日志
C1、步骤:
1、导包  如:import logging
2、调用相应的级别方法,记录日志信息  logging.debug('debug...');
C2、设置级别:
logging.basicConfig(level=logging.DEBUG)
提示:
1、默认级别为:logging.WARNING
2、设置级别时调用的是logging文件夹下面的常量(DEBUG),而不是调用小写的方法
3、切记:设置级别后,日志信息只会记录大于等于此级别的信息;C3、设置日志格式:
默认的日志格式为:
日志级别:Logger名称:日志内容自定义日志格式:
logging.basicConfig(format="%(levelname)s:%(name)s:%(message)s");format参数可能用到的:
占位符            描述
%(name)s               Logger的名字
%(levelno)s        数字形式的日志级别
%(levelname)s        文本形式的日志级别                   ***
%(pathname)s        调用日志输出函数模块的完整路径名,可能没有
%(filename)s         调用日志输出函数的模块的文件名              ***
%(module)s         调用日志输出函数的模块名
%(funcName)s          调用日志输出函数的函数名
%(lineno)d        调用日志输出的语句所在的代码行        ***
%(created)f        当前时间,用UNIX标准的表示 时间的浮点数表示
%(relativeCreated)d     输出日志信息时,自Logger创建以来的毫秒数
%(asctime)s        字符串形式的当前时间。默认格式是“2003-07-07 164945897****
%(thread)d        线程ID。可能没有
%(threadName)s        线程名。可能没有
%(process)d        线程ID。可能没有
%(message)s        用户输出的消息                ***#设置日志格式的示例代码
fmt='%(asctime)s %(levelname)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s'
logging.basicConfig(level=logging.INFO,format=fmt);C4、将日志信息输出到文件中:
默认情况下Python的logging模块将日志打印到了标准输出中(控制台)
将日志信息输出到文件中:
logging.basicConfig(filename='a.log');最终代码:
#导包
import logging;
#设置日志格式
fmt='%(asctime)s %(levelname)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s'
#设置日志级别\格式\设置日志保存到指定文件中
logging.basicConfig(level=logging.INFO,format=fmt,filename='./logs/log01.log');  #要用大写的INFO,大写的是变量,小写的是方法
#调用指定级别,输入日志信息     默认只显示warnning及以上的级别。在加入上面那句设置级别之后才会显示全部级别
logging.debug('this is a debug....')
logging.info('info....')
logging.warning("warning");
logging.error('error');
logging.critical('critical');在logs文件夹里成生的log01.log文件内容是这样子的:
2020-05-21 14:39:36,731 INFO [root] [test01_logging01.py(:12)] - info....
2020-05-21 14:39:36,731 WARNING [root] [test01_logging01.py(:13)] - warning
2020-05-21 14:39:36,731 ERROR [root] [test01_logging01.py(:14)] - error
2020-05-21 14:39:36,731 CRITICAL [root] [test01_logging01.py(:15)] - criticalPS:如果想要把message里的内容写成中文而不显示乱码:
在logging.basicConfic这里按住basicConfic的ctr键进入其底层代码__init__文件里改一下底层代码,但是暂时不要这样子。日志的使用实例:
step1、先在tool文件夹里加上get_log.py文件,源代码如下:
#导包
import logging;
#定义和获取Logging函数
def get_logging():fmt='%(asctime)s %(levelname)s [%(name)s] [%(filename)s(%(funcName)s:%(lineno)d)] - %(message)s';logging.basicConfig(level=logging.INFO,filename="../log/log01.log",format=fmt);return logging;step2、在base.py文件里实例化get_logging和导包,然后在每一个操作前面或后面加上log.info(),如下面源码所示:from selenium import webdriver;
from selenium.webdriver.support.wait import WebDriverWait
import time;
from testwo.tool.get_log import get_logging
log=get_logging();
class Base:#初始化方法def __init__(self, driver):log.info("初始化driver{}".format(driver));self.driver = driver;def base_find_element(self,loc,timeout=30,poll=0.5):  #设置后面两个参数的目的是为了有些场景的等待时间可能 会是2秒或其他时长,如果不传参就默认30秒,如果传参就按实际参数来等待log.info('正在查找元素:{}'.format(loc));#使用显式等待找到一个元素return WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll).until(lambda x:x.find_element(*loc)); #loc是位置#点击方法def base_click(self,loc):log.info('正在点击元素:{}'.format(loc));self.base_find_element(loc).click();#输入方法def base_input(self,loc,value):log.info('正在给元素{}输入内容:{}'.format(loc,value));el=self.base_find_element(loc);el.clear();log.info('正在清空{}的值'.format(loc));el.send_keys(value);log.info('正在给元素{}输入内容'.format(loc));#获取文件方法def base_get_text(self,loc):log.info('正在获取元素:{}的文本'.format(loc));return self.base_find_element(loc).text;#截图方法def base_get_image(self):self.driver.get_screenshot_as_file('../image/{}.png'.format(time.strftime("%Y_%m_%d %H_%M_%S")));# 查找元素判断是否操作成功# 思路封装def base_if_success(self,loc):try:self.base_find_element(loc,timeout=2);log.info("判断元素:{} 存在".format(loc));return True;except:log.info("判断元素:{} 不存在".format(loc))return False;step3、在test_login.py文件里导包和实例化,并在相应的地方加上log.error:#导包
import unittest;
from parameterized import parameterized
from testwo.base.get_driver import GetDriver
from testwo.page.page_login import PageLogin
from testwo.tool.read_json import read_json
from testwo.tool.get_log import get_logging
log=get_logging();
def get_data():datas=read_json('login.json');#新建空列表arrs=[]for data in datas.values():arrs.append((data['username'],data['pwd'],data['code'],data['expect'],data['success']));return arrs;
class LestLogin(unittest.TestCase):login=None;@classmethoddef setUpClass(cls):try:# 获取drivercls.driver = GetDriver().get_driver();# 初始化页面对象cls.login=PageLogin(cls.driver);cls.login.page_click_login_link();except Exception as e:log.error(e);@classmethoddef tearDownClass(cls):cls.login.driver.quit();#登录测试方法@parameterized.expand(get_data())def test_login(self,username,pwd,code,expect_result,success):#调用登录方法self.login.page_login(username,pwd,code);if success:#判断“退出”是否存在try:self.assertTrue(self.login.page_login_success());#点击退出self.login.page_click_logout();try:self.assertTrue(self.login.page_logout_success());except:self.login.page_get_screenshot();# 点击登录连接self.login.page_click_login_link();except Exception as e:self.login.page_get_screenshot();log.error(e);else:#获取登录后提示信息msg=self.login.page_get_err_info();print('错误信息是:',msg)try:self.assertEqual(msg,expect_result);except Exception as e:self.login.page_get_screenshot();log.error(e);# except AssertionError:#     self.login.page_get_screenshot();raise;运行结果生成的log01.log文件如下所示(部分):在log01.log文件那里右键---show in exploer,然后再用记事本打开:(可以ctr+F查找ERROR关键字来看错误信息)2020-05-21 16:46:54,709 INFO [root] [base.py(__init__:9)] - 初始化driver
2020-05-21 16:46:54,752 INFO [root] [base.py(base_click:17)] - 正在点击元素:('css selector', '.pull-right>a')
2020-05-21 16:46:54,775 INFO [root] [base.py(base_find_element:12)] - 正在查找元素:('css selector', '.pull-right>a')
2020-05-21 16:46:55,600 INFO [root] [base.py(base_input:21)] - 正在给元素('id', 'inputName')输入内容:shuiqingfu
2020-05-21 16:46:55,601 INFO [root] [base.py(base_find_element:12)] - 正在查找元素:('id', 'inputName')
2020-05-21 16:46:55,672 INFO [root] [base.py(base_input:24)] - 正在清空('id', 'inputName')的值
2020-05-21 16:46:55,727 INFO [root] [base.py(base_input:26)] - 正在给元素('id', 'inputName')输入内容
2020-05-21 16:46:55,731 INFO [root] [base.py(base_input:21)] - 正在给元素('name', 'password')输入内容:
2020-05-21 17:14:43,055 INFO [root] [base.py(base_find_element:12)] - 正在查找元素:('id', 'user.errors')
2020-05-21 17:14:43,566 ERROR [root] [test_login.py(test_login:59)] -  :: 验证码错误 != 账号不存在使用日志的高级用法:
日志封装:
#定义获取日志类#定义类属性 logger=None@classmethod#定义获取logger日志器的类方法if cls.logger is None:   #判断类属性logger是否为空#获取日志器对象#设置日志器级别#获取 控制台处理器#获取文件处理器#获取格式器#将格式器添加到处理器中#将格式器添加到日志器中return 类属性 logger注意:1、以上条件无论是否成立,最后都会返回类属性logger2、当第一次调用时,条件一定成立,将类属性logger设置不为空3、当第二次以上调用时,永远返回第一次设置的类属性对象。具体源码:
#导包
import logging.handlers;
class GetLogger:logger=None;@classmethoddef get_logger(cls):if cls.logger is None:#获取日志器cls.logger=logging.getLogger();#设置日志器 级别cls.logger.setLevel(logging.INFO);#获取处理器 控制台sh=logging.StreamHandler();#获取处理器 文件--以时间分隔th=logging.handlers.TimedRotatingFileHandler(filename="../log/log02.log",when='midnight',interval=1,backupCount=30,encoding='utf-8');#设置格式器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.logger;#测试效果,包括中文if __name__=='__main__':logger=GetLogger().get_logger();logger.info("info信息被执行")logger.error("error信息被执行");然后在base.py和test.login.py文件里,将:
log=get_logger()
改成:
log=GetLogger().get_logger();
并且重新导包:
from testwo.tool.logger import GetLogger;之后运行test_login.py生成的日志就是(部分,可以正常显示中文):
2020-05-21 20:57:15,428 INFO [root] [base.py(__init__:12)] - 初始化driver
2020-05-21 20:57:15,429 INFO [root] [base.py(base_click:20)] - 正在点击元素:('css selector', '.pull-right>a')
2020-05-21 20:57:15,429 INFO [root] [base.py(base_find_element:15)] - 正在查找元素:('css selector', '.pull-right>a')最后:项目实战了
一、自动化测试的流程
1、需求分析
2、挑选适合做自动化测试的功能
3、设计测试用例
4、搭建自动化测试环境【可选】
5、设计自动化测试项目的架构【可选】
6、编写代码
7、执行测试用例
8、生成测试报告并分析结果实际工作中的流程:
1、将功能用例转化自动化用例(在功能用例模板后新增一列是否自动化)
2、搭建自动化测试环境(本机执行自动化的依赖环境:python\pycharm\浏览器、浏览器驱动、selenium\parameterized)
3、搭建自动化框架(PO模式+数据驱动+log+报告)   ps:unittest是一个用例管理和执行的框架
4、编写代码
5、执行用例
6、生成报告\分析log项目需求:
登录商城、搜索商品并添加到购物车、下订单、支付整个流程
用例使用正向用例自动化测试结构:
1、base
2、page
3、scripts
4、tool
5、data
6、log
7、image
8、report根据用例决定base.py文件里有哪些方法:
from selenium import webdriver;
from selenium.webdriver.support.wait import WebDriverWaitclass Base:def __init__(self,driver):self.driver=driver;#查找元素 方法 封闭def base_find_element(self,loc,timeout=30,poll=0.5):#使用显式等待查找元素return WebDriverWait(self.driver,timeout=timeout,poll_frequency=poll).until(lambda x:x.find_element(*loc));#点击元素def base_click(self,loc):self.base_find_element(loc).click();#输入元素def base_input(self,loc,value):el=self.base_find_element(loc);el.clear();el.send_keys(value);#获取文本信息def base_get_text(self,loc):return self.base_find_element(loc).text;#截图def base_get_screenshot(self):self.driver.get_screenshot_as_file("../image/{}.png".format("%Y_%m_%d %H_%M_%S"));#判断元素是否存在的方法def base_element_is_exist(self,loc):try:self.base_find_element(loc,timeout=2);return True;except:return False;

web自动化测试笔记相关推荐

  1. WEB自动化测试笔记完整整理

    WEB自动化测试笔记完整整理 直接等待 强制等待,线程休眠一段时间 from time import sleeptime.sleep(3) 隐式等待 设置一个等待时间,轮询查找元素是否出现,如果没有出 ...

  2. Web自动化测试教程

    转载自python+selenium自动化软件测试(第2章):WebDriver API - Web自动化测试 - 博客园 (cnblogs.com) 目录 1.1 操作元素基本方法 1.1.1 打开 ...

  3. 13z Web自动化测试 - 软件测试

    软件测试所有内容笔记正在陆续更新中,笔记已经在本地记录,全部为自己手动记录的笔记及总结,正在开始更新中,后续会逐步更新并完善到 软件测试学习内容总结 专栏. 本节内容:Web自动化测试 文章目录 1 ...

  4. 开源 软件测试自动化工具,开源Web自动化测试工具Selenium IDE

    Selenium IDE(也有简写SIDE的)是一款开源的Web自动化测试工具,支持测试用例的录制与回放. 只要在浏览器里装一下插件,就可以开始使用,简直是"开箱即用".我们相信测 ...

  5. 基于python的界面自动化测试-基于Selenium+Python的web自动化测试框架

    一.什么是Selenium? Selenium是一个基于浏览器的自动化测试工具,它提供了一种跨平台.跨浏览器的端到端的web自动化解决方案.Selenium主要包括三部分:Selenium IDE.S ...

  6. web自动化测试---概述

    最早的时候是做功能测试,web都是自己手工点击看看有没问题,没有系统的进行测试,更别说自动化测试了,那是一段不堪回首的往事,就是因为这,很多问题都流出去了,这是作为测试人员的一大失职,痛定思痛,开始学 ...

  7. web python 自动化是什么_Selenium 凭什么成为 Web 自动化测试的首选?(内附源码)...

    原标题:Selenium 凭什么成为 Web 自动化测试的首选?(内附源码) 自动化 · 工具 1.QTP QTP是一个商业化的功能测试工具,收费,支持web,桌面自动化测试. 2. Selenium ...

  8. web自动化测试常见面试题

    一.找不到元素可能出现的原因: 1.元素表达式错误 2.不在指定的frame 3.等待时间短,页面加载速度慢 4.执行脚本打开了新的页面,不在指定的窗口中 二.优化web自动化测试效率 避免使用强制等 ...

  9. Web自动化测试理论知识

    Web 自动化理论知识 1.自动化测试概述 概念:用工具代替/辅助人工完成完成软件测试活动的过程 特点:     可以对程序的新版本自动执行回归测试     可以执行一些手工测试困难或不可能进行的测试 ...

最新文章

  1. vs 中大括号之间垂直虚线显示
  2. [0] OpenCV_Notes - 琐碎
  3. 【EasyUI】关于EasyUI中numberbox onblur事件失效的问题
  4. JMeter的PUT请求,响应结果中文出现乱码的解决方法
  5. mplab x ide 中文使用手册_SCI必备利器:翻译又快又准,强推这款超牛X的神器!...
  6. 柱坐标系下的ns方程_麦克斯韦方程组小结
  7. 程序员求职面试丨面试必备之终极指导篇,掌握这些,面试不再困难!
  8. python基本数据类型及语法
  9. 一个搜集大量网页特效的网站
  10. ASP.NET架构分析
  11. Spring 整合Quartz 2实现定时任务五:集群、分布式架构实现探讨
  12. 服务器安装数据库显示启动服务,安装数据库没有启动服务器服务
  13. PHP 日期时间类 Carbon 的常见用法
  14. 一次ARP***的处理过程
  15. react-native0.66==windows环境搭建、demo测试
  16. 07_第七章 迪克斯特拉算法
  17. 求1-1/2+1/3-1/4+...+1/99-1/100。
  18. Linux如何查看当前Ubuntu系统的版本
  19. 苹果Arm芯片适配开发 (Apple Silicon)
  20. 新华社客户端文章:区块链金融:新蓝海还是新挑战

热门文章

  1. mi8se android9,小米小米 8SE(安卓9.0)刷机解锁教程,看教程秒懂刷机,亲测可用...
  2. 如何做个网站-纯小白
  3. 成功说服别人的20个技巧
  4. JAVA2048感受心得_2048游戏心得大分享 不看你就OUT啦
  5. 0x0D 0x0A
  6. IDEA import导入的类明明存在,却飘红,你可以这样做
  7. 火炬开发区理工学校计算机等级考,我校召开2018下半年全国计算机等级考试考务工作会...
  8. LeetCode T46 Permutations
  9. Python之dir()与__dict__的区别
  10. 国家/行业标准查询及下载全流程