什么是自动化测试?javascript
把人对软件的测试行为转化为由机器执行测试行为的一种实践, 自动化测试用例的维护成本高于其节省的测试成本时, 自动化测试就失去价值与意义,在这样的项目中推动自动化测试就会得不偿失.
自动化测试的优势?css
能够替代大量的手工机械重复性操做. 自动化测试能够大幅提高回归测试的效率,很是适合敏捷开发过程; 能够高效实现某些手工测试没法完成或者代价巨大的测试类型. 能够保证每次测试执行的操做以及验证的一致性和可重复性,避免人为的遗漏或疏忽。
自动化测试的缺点?html
并不能取代手工测试,只能替代手工测试中执行频率高、机械化的重复步骤。不要奢望全部的测试都自动化,不然必定会得不偿失。 自动测试远比手动测试脆弱,没法应对被测系统的变化,自动化测试用例的维护成本一直居高不下。对于执行过程当中出现的明显错误和意外事件,自动化测试没有任何处理能力。 自动化测试用例的开发工做量远大于单次的手工测试. 手工测试发现的缺陷数量一般比自动化测试要更多,而且自动化测试仅仅能发现回归测试范围的缺陷。 测试的效率很大程度上依赖自动化测试用例的设计以及实现质量,不稳定的自动化测试用例实现比没有自动化更糟糕。 实行自动化测试的初期,用例开发效率一般都很低,大量初期开发的用例一般会在整个自动化测试体系成熟,和测试工程师全面掌握测试工具后,须要重构。 业务测试专家和自动化测试专家一般是两批人,前者懂业务不懂自动化技术,后者懂自动化技术但不懂业务,只有两者紧密合做,才能高效开展自动化测试。 自动化测试开发人员必须具有必定的编程能力,这对传统的手工测试工程师会是一个挑战。
什么样的项目适合自动化测试?前端
第一, 需求稳定,不会频繁变动。需求不稳定,需求变动频繁, 界面变化,或者是业务流程变化频繁不适合. 第二, 研发和维护周期长,须要频繁执行回归测试。对于短时间的一次性项目,我以为你应该选择手工探索式测试,以发现缺陷为第一要务。而对于一些中长期项目,个人建议是:对比较稳定的软件功能进行自动化测试,对变更较大或者需求暂时不明确的功能进行手工测试,最终目标是用 20% 的精力去覆盖 80% 的回归测试。 第三, 须要在多种平台上重复运行相同测试的场景. 第四, 测试项目经过手工测试没法实现或手工成本过高。全部的性能和压力测试,很难经过手工方式实现。 第五, 被测软件的开发较为规范,可以保证系统的可测试性。 第六, 测试人员已经具有必定的编程能力。
软件开发各阶段都有哪些自动化测试技术?java
单元测试、代码级集成测试、Web Service 测试和 GUI 测试阶段的自动化技术
单元测试的自动化技术包括:python
不只仅指测试用例执行的自动化,还包含如下五个方面: 用例框架代码生成的自动化.部分测试输入数据的自动化生成; 自动桩代码的生成;被测代码的自动化静态分析(经常使用的代码静态分析工具备 Sonar 和 Coverity);测试覆盖率的自动统计与分析。
代码级集成测试的自动化技术:android
指将已经开发完成的软件模块放在一块儿测试, 关注点更多的是软件模块之间的接口调用和数据传递。 代码级集成测试与单元测试最大的区别只是,代码级集成测试中被测函数内部调用的其余函数必须是真实的,不容许使用桩代码代替,而单元测试中容许使用桩代码来模拟内部调用的其余函数。 如今的开发理念追求的是系统复杂性的解耦,会去尽可能避免“大单体”应用,采用 Web Service 或者 RPC 调用的方式来协做完成各个软件功能。因此如今的软件企业,尤为是互联网企业,基本不会去作代码级集成测试.
Web Service 测试的自动化技术:web
指 SOAP API 和 REST API 这两类 API 测试,典型是采用 SoapUI 或 Postman 等相似的工具。但这类测试工具基本都是界面操做手动发起 Request 并验证 Response,因此难以和 CI/CD 集成,因而就出现了 API 自动化测试框架。 **对于基于代码的 API 测试用例,一般包含三大步骤:**准备 API 调用时须要的测试数据;准备 API 的调用参数并发起 API 的调用;验证 API 调用的返回结果。 最流行的 API 自动测试框架是 REST Assured,它能够方便地发起 Restful API 调用并验证返回结果. Web Service 测试“自动化”的内涵不只仅包括 API 测试用例执行的自动化,还包括如下四个方面: 测试脚手架代码的自动化生成;部分测试输入数据的自动生成;Response 验证的自动化;基于 SoapUI 或者 Postman 的自动化脚本生成。
GUI 测试的自动化技术chrome
核心思想是基于页面元素识别技术,对页面元素进行自动化操做,以模拟实际终端用户的行为并验证软件功能的正确性。 **GUI** **自动化测试主要分为两大方向,传统 Web 浏览器和移动端原生应用(Native App)的 GUI 自动化。两者采用的具体技术差异很大,用例设计的思路相似。Web端有selenium,** **Micro Focus** **的 UFT(前身是 HP 的 QTP).移动端有Appium等.** GUI 自动化测试的技术、原理和行业最佳实践。 GUI 测试中两个很是重要的概念:测试脚本和数据的解耦,以及页面对象(Page Object)模型.
数据驱动(Data-driven)测试:shell
测试脚本只有一份,其中须要输入数据的地方会用变量来代替,而后把测试输入数据单独放在一个文件中。这个存放测试输入数据的文件,一般是表格的形式,也就是最多见的 CSV 文件。而后,在测试脚本中经过 data provider 去 CSV 文件中读取一行数据,赋值给相应的变量,执行测试用例。接着再去 CSV 文件中读取下一行数据,读取完全部的数据后,测试结束。CSV 文件中有几行数据,测试用例就会被执行几回。 本质是实现了数据驱动的测试,让操做相同可是数据不一样的测试能够经过同一套自动化测试脚原本实现,只是在每次测试执行时提供不一样的测试输入数据。
数据驱动的好处:
很好地解决了大量重复脚本的问题,实现了“测试脚本和数据的解耦”。数据驱动测试的数据文件中不只能够包含测试输入数据,还能够包含测试验证结果数据,甚至能够包含测试逻辑分支的控制变量。数据驱动测试的思想不只适用于 GUI 测试,还能够用于 API 测试、接口测试、单元测试等。
页面对象模型(Page Object):
以页面(Web Page 或者 Native App Page)为单位来封装页面上的控件以及控件的部分操做。而测试用例,更确切地说是操做函数,基于页面封装对象来完成具体的界面操做,最典型的模式是“XXXPage.YYYComponent.ZZZOperation”。
如何把控操做函数的粒度?
操做函数的粒度是指,一个操做函数到底应该包含多少操做步骤才是最合适的。以完成一个业务流程(business flow)为主线,抽象出其中的“高内聚低耦合”的操做步骤集合,操做函数就由这些操做步骤集合构成。
如何衔接两个操做函数之间的页面?
若是连续的两个操做函数之间没法用页面衔接,那就须要在两个操做函数之间加入额外的页面跳转代码,或者是在操做函数内部加入特定的页面跳转代码。
GUI测试建立测试数据的方法:
从建立的技术手段上来说,建立测试数据的方法主要分为三种:API 调用;数据库操做;综合运用 API 调用和数据库操做。 从建立的时机来说,建立测试数据的方法主要分为两种:测试用例执行过程当中,实时建立测试数据,咱们一般称这种方式为 On-the-fly。测试用例执行前,事先建立好“开箱即用”的测试数据,一般称这种方式为 Out-of-box。 对于页面对象自动生成,商用测试软件已经实现。若是选择开源测试框架,就须要本身实现这个功能了。 GUI 测试数据自动生成,主要是基于测试输入数据的类型以及对应的自定义规则库实现的,而且对于多个测试输入数据,能够基于笛卡尔积来自动组合出完整的测试用例集合。 对于无头浏览器,你能够把它简单地想象成运行在内存中的浏览器,它拥有完整的浏览器内核。与普通浏览器最大的不一样是,它在执行过程当中看不到运行的界面。目前,Headless Chrome 结合 Puppeteer 是最早进的无头浏览器方案,若是感兴趣,你能够下载试用
GUI测试的稳定性:
要提升 GUI 测试稳定性,首先你须要知道究竟是什么缘由引发的不稳定。你必须找出尽量多的不稳定因素,而后找到每一类不稳定因素对应的解决方案。
五种形成 GUI 测试不稳定的因素:非预计的弹出对话框;页面控件属性的细微变化;被测系统的 A/B 测试,随机的页面延迟形成控件识别失败;测试数据问题。
非预计的弹出对话框能够:
(1) 当自动化脚本发现控件没法正常定位,或者没法操做时,GUI 自动化框架自动**进入“异常场景恢复模式**. 在“异常场景恢复模式”下,GUI 自动化框架依次检查各类可能出现的对话框,一旦确认了对话框的类型,当即执行预约义的操做(好比,单击“肯定”按钮,关闭这个对话框),接着重试刚才失败的步骤。而对于新类型的对话框,只能经过自动化的方式尝试点击上面的按钮进行处理。每当发现一种潜在会弹出的对话框,咱们就把它的详细信息(包括对象定位信息等)更新到“异常场景恢复”库中,下次再遇到相同类型的对话框时,系统就可自动关闭。
页面控件属性的细微变化:
采用“组合属性”定位控件会更精准**,并且成功率会更高,若是能在**此基础上加入“模糊匹配”技术**,能够进一步**提升控件的识别率**。可是,开源的 GUI 自动化测试框架,目前尚未现成的框架直接支持模糊匹配,一般须要你进行二次开发,实现思路是:实现本身的对象识别控制层,也就是在本来的对象识别基础上额外封装一层,在这个额外封装的层中加上模糊匹配的实现逻辑。一般,不建议把模糊匹配逻辑以硬编码的方式写在代码里,而是引入规则引擎,将具体的规则经过配置文件的方式与代码逻辑解耦。
被测系统的 A/B 测试:
在测试脚本内部对不一样的被测版本作分支处理,脚本须要可以区分 A 和 B 两个的不一样版本,并作出相应的处理。
随机的页面延迟形成控件识别失败:
加入重试(retry)机制。重试机制是指,当某一步 GUI 操做失败时,框架会自动发起重试,重试**能够是步骤级别的**,**也能够是页面级别的**,甚至是业务流程级别的。对于开源 GUI 测试框架,重试机制每每不是自带的功能,须要本身二次开发来实现。须要特别注意的是,对于那些会修改一次性使用数据的场景,切忌不要盲目启用页面级别和**业务流程级别**的重试.
测试数据问题:略.
理想中的 GUI 测试报告
应该是由一系列按时间顺序排列的屏幕截图组成,而且这些截图上能够高亮显示所操做的元素,同时按照执行顺序配有相关操做步骤的详细描述。
开源 GUI 测试框架的测试报告实现思路:
利用 Selenium WebDriver 的 screenshot 函数在一些特定的时机(好比,页面发生跳转时,在页面上操做某个控件时,或者是测试失败时,等等)完成界面截图功能。具体到代码实现,**一般有两种方式:扩展 Selenium 本来的操做函数;在相关的 Hook 操做中调用 screenshot 函数。**
**第一,** **扩展 Selenium 本来的操做函数实现截图以及高亮显示操做元素的功能:** **本身实现的 click 函数被调用时:**首先,用 Javascript 代码高亮显示被操做的元素,高亮的实现方式就是利用 JavaScript 在对象的边框上渲染一个 5-8 个像素的边缘;而后,调用 screenshot 函数完成点击前的截图;最后,调用 Selenium 原生的 click 函数完成真正的点击操做。那么,之后凡是须要调用 click 函数时,都直接调用这个本身封装的 click 函数,直接获得高亮了被操做对象的界面截图。 **第二,** **在相关的 Hook 操做中调用 screenshot 函数实现截图以及高亮显示操做元素的功能。** **第三,** **大型全球化电商网站的 GUI 自动化测试如何开展(若是你所在的企业或者项目正在大规模开展 GUI 测试,而且准备使用页面对象模型以及业务流程封装等最佳实践的话):**
GUI 测试一般只覆盖最核心且直接影响主营业务流程的 E2E 场景。
按照自底向上的顺序分层次介绍 GUI 自动化的测试策略。 首先,要从前端组件的级别来保证质量,也就是须要对那些自定义开发的组件进行完整全面的测试。公共组件库会被不少上层的前端模块依赖,它的质量将直接影响这些上层模块的质量,因此咱们每每会对这些公共组件进行严格的单元测试。最经常使用的方案是:基于 Jest 开展单元测试,并考量 JavaScript 的代码覆盖率指标。 完成单元测试后,每每还会基于被测控件构建专用的测试页面,在页面层面再次验证控件相关的功能和状态。这部分测试工做也须要采用自动化的形式实现,具体的作法是: 1. 先构建一个空页面,并加入被测控件,由此能够构建出一个包含被测控件的测试页面,这个页面每每被称为 Dummy Page; 2. 从黑盒的角度出发,在这个测试页面上经过手工和自动化的方式操做被测控件,并验证其功能的正确性。 对于自动化的部分,须要基于 GUI 自动化测试框架开发对应的测试用例。这些测试用例,每每采用和 GUI E2E 同样的测试框架,也是从黑盒的角度来对被测控件作功能验证。 **其次,每个前端模块,都会构建本身的页面对象库,而且在此基础上封装开发本身的业务流程脚本。这些业务流程的脚本,能够组装成每一个前端模块的测试用例。最后,组合各个前端模块,并站在终端用户的视角,以黑盒的方式使用网站的端到端(E2E)测试。**
monkey测试:
测试软件的稳定性,健壮性的方法,通常能够经过测试过程当中打印的日志来发现问题。Monkey是经过命令行来对APP进行测试的工具,容许在模拟器里或真机上。向系统发送伪随机用户时间流实现对应用程序进行压力测试;
环境搭建:
win10需按照ADB工具, XA,而后再配置变量XB
实践: 在手机开发者选项中,勾上USB调试。使用adb命令查看已链接设备:$adb devices
关闭adb的后台进程: adb kill-server 让手机脱离USB线的TCP链接方式: adb tcpip 开启tcp链接方式链接手机: adb connect 收集日志数据,用于后续的分析,好比耗电量: adb bugreport 发送压测命令:对随机应用执行100条monkey命令:adb shell monkey 1000 对特定应用进行monkey测试:adb shell monkey -P XXX.apk -v 测试次数 APP信息:获取当前界面信息: adb shell dumpsys activity top 获取任务列表: adb shell dumpsys activity activities 得到内存信息: adb shell dumpsys meminfo com.android.settings 获取cpu信息: adb shell dumpsys cpuinfo 获取特定包基本信息: adb shell dumpsys package xx 获取当前activity: adb shell dumpsys activity top APP入口:adb logcat| findsdr -i displayed 或 appt dump badging xx.apk | grep lanunchable-activity 或 apkanalyzer 最新版本的sdk才有 启动应用: adb shell am start -n xxx -S 日志查询: adb logcat 当前应用查询 adb logcat | findstr Displayed ADB SHELL:自己Linux的shell,能够调用Android内置命令. adb shell dumpsys adb shell pm adb shell am adb shell ps adb shell monkey 清理应用缓存:adb shell pm clear 包名 显示经常使用uiautomator命令: adb shell uiautomator 显示经常使用输入命令: adb shell input
Web测试框架,丰富的API,支持多种语言编写测试脚本且可在多种浏览器执行测试脚本。
V1.0 和 V2.0 版本的技术方案是大相径庭的,V1.0 的核心是 Selenium RC,而 V2.0 的核心是 WebDriver, V3.0 相比 V2.0 并无本质上的变化,主要是增长了对 MacOS 的 Safari 和 Windows 的 Edge 的支持,并完全删除了对 Selenium RC 的支持。
server-client设计模式设计的。server端即浏览器。当咱们的脚本启动浏览器后,等待client发送请求并作出相应;client端即测试代码.
本地安装Python,在官网下载,安装时勾选path,安装完成后,在cmd中输入python,查看安装成功. 安装selenium,在cmd中输入pip install selenium 安装Chrome Webdriver:[官网](https://sites.google.com/a/chromium.org/chromedriver/downloads)
browser = webdriver.Chrome() browser = webdriver.Firefox() browser = webdriver.Safari() browser = webdriver.Ie()
from selenium import webdriver browser = webdriver.Chrome(executable_path="..\..\..\zc\chromedrive\chromedriver.exe") # executable_path来指定chromedirver路径 browser.get('https://www.baidu.com') print(browser.title) browser.quit()
# 经过 id 定位 dr.find_element_by_id("kw") # 经过name定位: dr.find_element_by_name("wd") # 经过class name定位: dr.find_element_by_class_name("s_ipt") # 经过tag name定位: dr.find_element_by_tag_name("input") # 经过 xpath 定位的几种写法 dr.find_element_by_xpath("//*[@id='kw']") dr.find_element_by_xpath("//*[@name='wd']") dr.find_element_by_xpath("//input[@class='s_ipt']") dr.find_element_by_xpath("/html/body/form/span/input") dr.find_element_by_xpath("//span[@class='soutu-btn']/input") dr.find_element_by_xpath("//form[@id='form']/span/input") dr.find_element_by_xpath("//input[@id='kw' and @name='wd']") # 经过 css 定位的几种写法 dr.find_element_by_css_selector("#kw") dr.find_element_by_css_selector("[name=wd]") dr.find_element_by_css_selector(".s_ipt") dr.find_element_by_css_selector("html > body > form > span > input") dr.find_element_by_css_selector("span.soutu-btn> input#kw") dr.find_element_by_css_selector("form#form > span > input") # 经过 link_text 定位 dr.find_element_by_link_text("新闻") dr.find_element_by_link_text("hao123") dr.find_element_by_partial_link_text("新") dr.find_element_by_partial_link_text("hao") dr.find_element_by_partial_link_text("123") 定位一组元素:WebDriver还提供8种用于定位一组元素的方法。 find_elements_by_id() find_elements_by_name() find_elements_by_class_name() find_elements_by_tag_name() find_elements_by_link_text() find_elements_by_partial_link_text() find_elements_by_xpath() find_elements_by_css_selector()
set_window_size()方法来设置浏览器的大小 , maximize_window() 全屏显示.如:browser.set_window_size(480,800) back()和 forward()方法来模拟后退和前进按钮, refresh()方法模拟F5刷新页面.
Clear()方法,清除文本. Send_keys(‘value’)方法,模拟键盘输入. Click()方法,单击元素. submit()方法用于提交表单. size: 返回元素的尺寸. text: 获取元素的文本. get_attribute(name): 得到属性值。is_displayed(): 设置该元素是否用户可见。
在 WebDriver中鼠标操做的方法封装在 ActionChains 类提供。经常使用方法以下: perform():执行全部 ActionChains 中存储的行为; move_to_element(): 鼠标悬停。 context_click(): 右击; double_click(): 双击; drag_and_drop(): 拖动; 如: # 引入 ActionChains 类 from selenium.webdriver.common.action_chains import ActionChains # 定位到要悬停的元素 cc = browser.find_element_by_xpath('//*[@id="content"]/div/div[1]/div[2]/ul/li[4]/a') # 对定位到的元素执行鼠标悬停操做 ActionChains(browser).double_click(cc).perform()
Keys()类提供了键盘上几乎全部按键的方法. # 引入 Keys 模块 from selenium.webdriver.common.keys import Keys #经常使用键盘方法: send_keys(Keys.BACK_SPACE) 删除键(BackSpace) send_keys(Keys.SPACE) 空格键(Space) send_keys(Keys.TAB) 制表键(Tab) send_keys(Keys.ESCAPE) 回退键(Esc) send_keys(Keys.ENTER) 回车键(Enter) send_keys(Keys.CONTROL,'a') 全选(Ctrl+A) send_keys(Keys.CONTROL,'c') 复制(Ctrl+C) send_keys(Keys.CONTROL,'x') 剪切(Ctrl+X) send_keys(Keys.CONTROL,'v') 粘贴(Ctrl+V) send_keys(Keys.F1) 键盘 F1 send_keys(Keys.F12) 键盘 F12
#测试时须要拿实际结果与预期结果进行比较,这个比较称为断言 title:用于得到当前页面的标题。 current_url:用户得到当前页面的URL。 text:获取搜索条目的文本信息。 #WebDriver提供两种类型的等待:显式等待和隐式等待。 显式等待:使WebdDriver等待某个条件成立时继续执行,不然在达到最大时长时抛出超时异常(TimeoutException)。 隐式等待:WebDriver提供了implicitly_wait()方法来实现隐式等待,默认设置为0。
from selenium import webdriver from selenium.webdriver.common.by import By from selenium.webdriver.support.ui import WebDriverWait from selenium.webdriver.support import expected_conditions as EC import time base_url = 'http://www.baidu.com/' driver = webdriver.Chrome('../tools/chromedriver.exe') driver.get(base_url) # 1.显示等待 # WebDriverWait(driver, timeout, poll_frequency=0.5, ignored_exceptions=None) # driver :浏览器驱动。 # timeout :最长超时时间,默认以秒为单位。 # poll_frequency :检测的间隔(步长)时间,默认为0.5S。 # ignored_exceptions :超时后的异常信息,默认状况下抛NoSuchElementException异常 # until(method, message=‘’)-----调用该方法提供的驱动程序做为一个参数,直到返回值为True。 # until_not(method, message=‘’)---调用该方法提供的驱动程序做为一个参数,直到返回值为False。 # presence_of_element_located()方法判断元素是否存在。 element = WebDriverWait(driver, 5, 0.5).until( EC.presence_of_element_located((By.ID, 'kw')) ) element.send_keys('要搜索的内容') time.sleep(3) driver.quit()
# 2. 隐式等待 from selenium.common.exceptions import NoSuchElementException from selenium import webdriver from time import ctime import time base_url2 = 'https://www.baidu.com/' browser = webdriver.Chrome('../tools/chromedriver.exe') # 设置隐式等待为10s browser.implicitly_wait(10) browser.get(base_url2) try: print(ctime()) browser.find_element_by_id('kw').send_keys('se') time.sleep(3) except NoSuchElementException as e: print(e) finally: print(ctime()) browser.quit()
WebDriver只能在一个页面上对元素识别与定位,对于frame/iframe表单内嵌页面上的元素没法直接定位。须要经过switch_to.frame()方法将当前定位的主体切换为frame/iframe表单的内嵌页面中。
如:browser.switch_to.frame(‘xx’) switch_to.frame() 默承认以直接取表单的id 或name属性。若是iframe没有可用的id和name属性,则能够经过下面的方式进行定位。 #先经过xpth定位到iframe xf = driver.find_element_by_xpath('//*[@id="x-URS-iframe"]') #再将定位对象传给switch_to.frame()方法 driver.switch_to.frame(xf) …… driver.switch_to.parent_frame() 除此以外,在进入多级表单的状况下,还能够经过switch_to.default_content()跳回最外层的页面。
WebDriver提供了switch_to.window()方法,能够实如今不一样的窗口之间切换。
current_window_handle:得到当前窗口句柄。
window_handles:返回全部窗口的句柄到当前会话。
switch_to.window():用于切换到相应的窗口,与上一节的switch_to.frame()相似,前者用于不一样窗口的切换,后者用于不一样表单之间的切换。
from selenium import webdriver import time base_url = 'https://www.baidu.com/' browser = webdriver.Chrome('../tools/chromedriver.exe') # 隐式等待10秒 browser.implicitly_wait(10) browser.get(base_url) # 得到搜索窗口的句柄 search_windows = browser.current_window_handle browser.find_element_by_link_text('登陆').click() browser.find_element_by_link_text('当即注册').click() # 活得当前打开窗口的句柄 all_handles = browser.window_handles # 进入注册窗口 for handle in all_handles: if handle != search_windows: browser.switch_to.window(handle) print('now register window!') browser.find_element_by_name('account').send_keys('username') browser.find_element_by_name('password').send_keys('password') time.sleep(2) browser.quit()
WebDriver中处理JavaScript所生成的alert、confirm以及prompt十分简单.
具体作法是使用 switch_to.alert 方法定位到 alert/confirm/prompt,而后使用text/accept/dismiss/ send_keys等方法进行操做。
text:返回 alert/confirm/prompt 中的文字信息。 accept():接受现有警告框。
dismiss():解散现有警告框。 send_keys(keysToSend):发送文本至警告框。keysToSend:将文本发送至警告框。
from selenium import webdriver from selenium.webdriver.common.action_chains import ActionChains import time base_url = 'https://www.baidu.com/' driver = webdriver.Chrome('../tools/chromedriver.exe') driver.implicitly_wait(10) driver.get(base_url) # 鼠标悬停至 “设置” 连接 link = driver.find_element_by_link_text('设置') ActionChains(driver).move_to_element(link).perform() # 打开搜索设置 driver.find_element_by_link_text('搜索设置').click() time.sleep(3) # 点击 “搜索设置” driver.find_element_by_class_name('prefpanelgo').click() time.sleep(3) # 接受警告框prefpanelgo driver.switch_to.alert.accept() time.sleep(3) driver.quit()
WebDriver提供了Select类来处理下拉框, Select类用于定位select标签。
select_by_value() 方法用于定位下接选项中的value值。
send_keys()方法来实现文件上传
from selenium import webdriver from selenium.webdriver.support.select import Select from time import sleep base_url = 'https://www.baidu.com/' driver = webdriver.Chrome('../tools/chromedriver.exe') driver.implicitly_wait(10) driver.get(base_url) # 鼠标悬停至“设置”连接 driver.find_element_by_name('设置').click() sleep(2) # 打开 “搜索设置” driver.find_element_by_name('搜索设置').click() sleep(2) # 搜索结果显示条数 # Select类用于定位select标签。 sel = driver.find_element_by_xpath("//select[@id='nr']") # select_by_value() 方法用于定位下接选项中的value值。 Select(sel).select_by_value('50') driver.quit()
经过input标签实现的上传功能,能够将其看做是一个输入框,即经过send_keys()指定本地文件路径的方式实现文件上传
from selenium import webdriver import os driver = webdriver.Chrome('../tools/chromedriver.exe') file_path = "file:///" + os.path.abspath('upfile.html') driver.get(file_path) # 定位上传按钮的位置 driver.find_element_by_name('file').send_keys(os.path.abspath('upfile.txt')) driver.quit()
get_cookies(): 得到全部cookie信息。 get_cookie(name): 返回字典的key为“name”的cookie信息。 add_cookie(cookie_dict) : 添加cookie。“cookie_dict”指字典对象,必须有name 和value 值。 delete_cookie(name,optionsString):删除cookie信息。“name”是要删除的cookie的名称,“optionsString”是该cookie的选项,目前支持的选项包括“路径”,“域”。 delete_all_cookies(): 删除全部cookie信息。 from selenium import webdriver from time import sleep base_url = 'https://www.baidu.com/' browser = webdriver.Chrome('../tools/chromedriver.exe') browser.get(base_url) # 1. 获取 cookie 信息 cookies = browser.get_cookies() print(cookies) sleep(2) browser.quit() # 2. cookie 写入 browser.add_cookie( { 'name': 'add-cookie', 'value': 'add-cookie-value' } ) # 遍历cookies打印cookie信息 for cookie in browser.get_cookies(): print("%s ---> %s" % (cookie['name'], cookie['value'])) sleep(2) browser.quit()
WebDriver提供了execute_script()方法来执行JavaScript代码。
WebDriver提供了截图函数get_screenshot_as_file()来截取当前窗口。
rom selenium import webdriver from time import sleep base_url = 'https://www.baidu.com' browser = webdriver.Chrome('../tools/chromedriver.exe') browser.get(base_url) # window.scrollTo()方法用于设置浏览器窗口滚动条的水平和垂直位置。方法的第一个参数表示水平的左间距,第二个参数表示垂直的上边距。 browser.set_window_size(500, 500) browser.find_element_by_id('kw').send_keys('百度') browser.find_element_by_id('su').click() sleep(2) # 经过javascript设置浏览器窗口的滚动条位置 js = "window.scrollTo(100, 450);" browser.execute_script(js) sleep(2) browser.quit()
webdriver 提供了截图函数 get_screenshot_as_file() 来截取当前窗口
from selenium import webdriver from time import sleep base_url = 'http://www.baidu.com/' browser = webdriver.Chrome('../tools/chromedriver.exe') browser.get(base_url) browser.find_element_by_id('kw').send_keys('python selenium') browser.find_element_by_id('su').click() sleep(2) # 截取当前窗口并指定报错截图的位置 # browser.get_screenshot_as_file('ScreenShot/14_screenShot.jpg') browser.get_screenshot_as_file('ScreenShot/14_screenShot.png') browser.quit()
close() 关闭单个窗口 quit() 关闭全部窗口
Python自带的单元测试框架,用于编写和运行可重复的测试,主要用于白盒测试和回归测试
(1)让测试具备持久性,测试与开发同步进行,测试代码与开发代码一并发布; (2)能够是测试代码与产品代码分离; (3)针对某一个类的测试代码只需少许改动就能够应用与另外一个类的测试; (4)使用断言方法判断指望值与实际值的差别,返回bool值; (5)测试驱动设备可使用共同的处理化变量或实例; (6)测试包结构便于组织集成运行。
unittest 要求单元测试类必须继承 unittest.TestCase,该类中的测试方法须要知足以下要求:测试方法应该没有返回值。测试方法不该该有任何参数。测试方法应以test 开头。
#导入 unittest 这个模块 import unittest #class 这一行是定义一个测试的类,并继承 unittest.TestCase 这个类 class IntegerArithmeticTestCase(unittest.TestCase): # 接下来是定义了两个测试case名称: testAdd和testMultiply四、注释里面有句话很重要: #test method names begin 'test*'--翻译:测试用例的名称要以 test 开头 def testAdd(self): # test method names begin with 'test' self.assertEqual((1 + 2), 3) self.assertEqual(0 + 1, 1) ##而后是断言 assert,这里的断言方法是 assertEqual-判断两个是否相等,这个断言能够是一个也能够是多个 def testMultiply(self): self.assertEqual((0 * 10), 0) self.assertEqual((5 * 8), 40) #if 下面的这个 unittest.main()是运行主函数,运行后会看到测试结果 if __name__ == '__main__': unittest.main()
一、setUp:在写测试用例的时候,每次操做其实都是基于打开浏览器输入对应网址这些操做,这个就是执行用例的前置条件。
二、tearDown:执行完用例后,为了避免影响下一次用例的执行,通常有个数据还原的过程,这就是执行用例的后置条件。
三、不少小伙伴执行完用例,都不去作数据还原,以至于下一个用例执行失败,这就是典型的本身给本身挖坑埋本身,本身坑本身,习惯很差。
四、前置和后置都是非必要的条件,若是没有也能够写 pass
def setUP(self): pass def tearDown(self): pass
11 import unittest 12 13 #4.前置、后置 和运行测试 14 class Test(unittest.TestCase): 15 16 def setUp(self): 17 pass #若是没有能够不写或者pass代替 18 19 def tearDown(self): 20 pass 21 22 def testSubtract(self): # test method names begin with 'test' 23 result = 6-5 #实际结果 24 hope = 1 #指望结果 25 self.assertEqual(result, hope) 26 27 def testDivide(self): 28 result = 7 / 2 # 实际结果 29 hope = 3.5 # 指望结果 30 self.assertEqual(result, hope) 31 32 if __name__ == '__main__': 33 unittest.main()
unittest的属性:
unittest.TestCase**:TestCase类,全部测试用例类继承的基本类。 class BaiduTest(unittest.TestCase): unittest.main(): 能够方便的将一个单元测试模块变为可直接运行的测试脚本, main()方法使用TestLoader类来搜索全部包含在该模块中以“test”命名开头的测试方法,并自动执行他们。 执行方法的默认顺序是:根据ASCII码的顺序加载测试用例,数字与字母的顺序为:0-9,A-Z,a-z。因此以A开头的测试用例方法会优先执行,以a开头会后执行。 unittest.TestSuite():unittest框架的TestSuite()类是用来建立测试套件的。 unittest.TextTextRunner(): unittest框架的TextTextRunner()类,经过该类下面的run()方法来运行suite所组装的测试用例,入参为suite测试套件。 unittest.defaultTestLoader(): defaultTestLoader()类,经过该类下面的discover()方法可自动更具测试目录start\_dir匹配查找测试用例文件(test\*.py),并将查找到的测试用例组装到测试套件,所以能够直接经过run()方法执行discover。用法以下: discover=unittest.defaultTestLoader.discover(test_dir, pattern='test_*.py') unittest.skip():装饰器,当运行用例时,有些用例可能不想执行等,可用装饰器暂时屏蔽该条测试用例。一种常见的用法就是好比说想调试某一个测试用例,想先屏蔽其余用例就能够用装饰器屏蔽。 @unittest.skip(reason): skip(reason)装饰器:无条件跳过装饰的测试,并说明跳过测试的缘由。 @unittest.skipIf(reason): skipIf(condition,reason)装饰器:条件为真时,跳过装饰的测试,并说明跳过测试的缘由。 @unittest.skipUnless(reason): skipUnless(condition,reason)装饰器:条件为假时,跳过装饰的测试,并说明跳过测试的缘由。 @unittest.expectedFailure(): expectedFailure()测试标记为失败。
TestCase类的属性以下:
setUp(): 用于测试用例执行前的初始化工做。如测试用例中须要访问数据库,能够在setUp中创建数据库链接并进行初始化。如测试用例须要登陆web,能够先实例化浏览器。 tearDown(): 用于测试用例执行以后的善后工做。如关闭数据库链接。关闭浏览器。 assert*():一些断言方法:在执行测试用例的过程当中,最终用例是否执行经过,是经过判断测试获得的实际结果和预期结果是否相等决定的。 ##!!注意,去掉\[ \] assertEqual(a,b,\[msg='测试失败时打印的信息'\]):断言a和b是否相等,相等则测试用例经过。 assertNotEqual(a,b,\[msg='测试失败时打印的信息'\]):断言a和b是否相等,不相等则测试用例经过。 assertTrue(x,\[msg='测试失败时打印的信息'\]):断言x是否True,是True则测试用例经过。 assertFalse(x,\[msg='测试失败时打印的信息'\]):断言x是否False,是False则测试用例经过。 assertIs(a,b,\[msg='测试失败时打印的信息'\]):断言a是不是b,是则测试用例经过。 assertNotIs(a,b,\[msg='测试失败时打印的信息'\]):断言a是不是b,不是则测试用例经过。 assertIsNone(x,\[msg='测试失败时打印的信息'\]):断言x是否None,是None则测试用例经过。 assertIsNotNone(x,\[msg='测试失败时打印的信息'\]):断言x是否None,不是None则测试用例经过。 assertIn(a,b,\[msg='测试失败时打印的信息'\]):断言a是否在b中,在b中则测试用例经过。 assertNotIn(a,b,\[msg='测试失败时打印的信息'\]):断言a是否在b中,不在b中则测试用例经过。 assertIsInstance(a,b,\[msg='测试失败时打印的信息'\]):断言a是是b的一个实例,是则测试用例经过。 assertNotIsInstance(a,b,\[msg='测试失败时打印的信息'\]):断言a是是b的一个实例,不是则测试用例经过。
TestSuite类的属性以下:(组织用例时须要用到)
addTest(): addTest()方法是将测试用例添加到测试套件中,以下方,是将test_baidu模块下的BaiduTest类下的test_baidu测试用例添加到测试套件。
suite = unittest.TestSuite() suite.addTest(test\_baidu.BaiduTest('test\_baidu'))
TextTextRunner的属性以下:(组织用例时须要用到)
run(): run()方法是运行测试套件的测试用例,入参为suite测试套件。
runner = unittest.TextTestRunner() runner.run(suite)
12 #4.执行顺序和运行测试 13 import unittest 14 15 class TestLogin(unittest.TestCase): 16 17 def setUp(self): 18 pass 19 def test_login_blog(self): 20 """登陆博客园 21 22 :return: 23 """ 24 print("登陆博客园") 25 def test_add_essay(self): 26 """ 添加随笔 27 28 :return: 29 """ 30 print("添加随笔") 31 def test_release_essay(self): 32 """ 发布随笔 33 34 :return: 35 """ 36 print("发布随笔") 37 def test_quit_blog(self): 38 """退出博客园 39 40 :return: 41 """ 42 print("退出博客园") 43 44 def tearDown(self): 45 pass 46 if __name__ == '__main__': 47 # 启动单元测试 48 # unittest.main() 49 50 # 获取TestSuite的实例对象 51 suite = unittest.TestSuite() 52 53 # 将测试用例添加到测试容器中 54 suite.addTest(TestLogin('test_login_blog')) 55 suite.addTest(TestLogin('test_add_essay')) 56 suite.addTest(TestLogin('test_release_essay')) 57 suite.addTest(TestLogin('test_quit_blog')) 58 59 # 建立TextTestRunner类的实例对象 60 runner = unittest.TextTestRunner() 61 runner.run(suite) 62 #unittest.TextTestRunner(verbosity=3).run(suite)
11 import unittest 12 #4.执行顺序和运行测试 13 import unittest 14 15 class TestLogin(unittest.TestCase): 16 17 def setUp(self): 18 pass 19 def test_1_login_blog(self): 20 """登陆博客园 21 22 :return: 23 """ 24 print("登陆博客园") 25 def test_2_add_essay(self): 26 """ 添加随笔 27 28 :return: 29 """ 30 print("添加随笔") 31 def test_3_release_essay(self): 32 """ 发布随笔 33 34 :return: 35 """ 36 print("发布随笔") 37 def test_4_quit_blog(self): 38 """退出博客园 39 40 :return: 41 """ 42 print("退出博客园") 43 44 def tearDown(self): 45 pass 46 if __name__ == '__main__': 47 # 启动单元测试 48 unittest.main()
官方文档
一个很是成熟的 Python 测试框架,能够作到作个场景的测试工做,如:单元测试、接口测试、web测试等。 pytest兼容unittest测试用例,可是反过来unittest不兼容pytest, 是一个插件化平台,丰富的插件扩展加强了它的功能,也能够根据本身的须要定制化开发本身的插件,很是的灵活
import pytest class TestClass(object): def test_one(self): print("one case...\n") x = "test" assert 'e' in x def test_two(self): print("two case...\n") x = "hello" assert hasattr(x, 'check') if __name__ == "__main__": pytest.main()
由Qameta Software团队开源的一款旨在于解决让每一个人能更容易生成并更简洁阅读的测试报告框架。它支持大多数的测试框架,如:Pytest、TestNG等,简单易用便于集成。
官网地址,注意必定别选最新的,还有项目名千万别以pytest开头
Allure要生效须要在测试文件和测试通配文件(conftest.py)中配置 allure。
pip3 install pytest pip3 install allure-pytest
前提配置Java1.8+的环境. 官网下载解压,配置Path,变量为安装文件的allure.bat文件. 在cmd中输入allure,查看是否安装成功.
import pytest import allure # allure.feature 定义功能 @allure.feature("报告购物车") class TestAllure(object): # 定义用户场景 @allure.story("加入购物车") def test_add_goods_cart(self): # 调用步骤函数 login("crisimple", "123456") # 将测试用例分红几个步骤,将测试步骤打印到测试报告中,步骤二 with allure.step("浏览商品"): # allure.attach--打印一些附加信息 allure.attach("商品1", "C") allure.attach("商品2", "C") # 步骤三 with allure.step("加入商品"): allure.attach("商品1", 2) allure.attach("商品2", 3) # 步骤四 with allure.step("校验商品"): allure.attach("商品1加入成功", "共2个") allure.attach("商品2加入失败", "共0个") @allure.story("继续购物") def test_continue_shopping_cart(self): login("crisimple", "123456") allure.attach("商品3", 4) print("继续购物成功") @allure.story("减小商品失败") def test_edit_shopping_cart(self): login("crisimple", "123") assert 0 @pytest.mark.skip(reason="删除购物车不执行") @allure.story("删除购物车") def test_delete_shopping_cart(self): login("crisimple", "123") print() # 将函数做为一个步骤,调用此函数时,报告中输出一个步骤,步骤名称一般时函数名,这样的函数一般称为步骤函数 @allure.step("用户登陆") def login(user, passwd): if user == "crisimple" and passwd == "123456": print(user, passwd) print("登陆成功") else: print(user, passwd) print("登陆失败,请从新尝试")
# 在文件地址打开cmd,假设文件名为test_demo.py,生成json格式运行结果 pytest --alluredir=report test_demo.py $命令中的 --alluredir=report 指明了生成的json结果文件存放的目录为当前目录下的report文件夹 # 使用`allure`生成最终的测试报告 allure generate report #实际内容须要 `allure` 进行渲染后才能看到 allure open allure-report
Feature: 标注主要功能模块 Story: 标注Features功能模块下的分支功能 Severity: 标注测试用例的重要级别 Step: 标注测试用例的重要步骤 Issue和TestCase: 标注Issue、Case,可加入URL
(1) 掘金博主
(2) unittest官方文档连接:中文文档,英文文档
(3) 实战接口项目
(4) 掘金博客_自动化测试**