1.1 软件测试分类
软件测试 V 模型:
需求分析---设计---编码
验收测试--------系统测试---集成测试—单元测试
单元测试:是对程序中的单个子程序或具有独立功能的代码段进行测试的过程
集成测试:检查模块之间的接口是否正确
系统测试:针对整个产品进行系统测试,验证系统是否满足了需求规格的定义,以及软件系统的正确性和性能等是否满足其规约所指定的需求
验收测试:确保软件准备就绪,向软件购买者展示该软件系统需求满足其用户的需求
黑盒测试:把软件看做一个黑盒子,我们不去关心盒子里面的结构,只关心软件的输入数据和输出结果。主要针对软件界面和软件功能进行测试
白盒测试:研究源代码和程序的执行结果。它是按照程序内部的结构测试程序,通过测试来检验产品内部动作是否按照设计规格说明书的规定正常进行,检验程序中的每条通路是否都能按预定要求正确工作
灰盒测试:既关注输出对于输入的正确性,同时也关注不像白盒那样详细、完整,只是通过一些表征性的现象、事件、标志来判断内部运行的状态。
冒烟测试:是指在对一个新版本进行系统大规模的测试之前,先验证一下软件的基本功能是否实现,是否具备可测性
回归测试:修改了旧代码后,重新进行测试以确认修改后没有引入新的错误或导致其他代码产生错误
随机测试:是指测试中的所有输入数据都是随机生成的,其目的是模拟用户的真实操作,并发现一些边缘性的错误。
1.2 分层的自动化测试
UI测试
集成/接口测试
单元测试
单元测试:单元测试框架,java的Junint、testNG,C#的Nuit,Python的unittest、pytest等
在自动化测试中最怕的是变化,因为变化的直接结果就是导致测试用例的运行失败,那么就需要对自动化脚本进行维护;如何控制失败,降低维护成本对自化的成败至关重要。
UI 层的自动化测试工具非常多,比较主流的是QTP,Robot Framework、watir、Selenium 等。
1.3 什么样的项目适合自动化测试
1.4 自动化测试及工具简述
自动化测试的概念有广义与狭义之分;广义上来讲所有借助工具来进行软件测试都可以称之为自动化测试;从狭义来讲,主要指基于UI层的自动化测试;除此之外还有基代码编写阶段的单元自动化测试,基本集成测试阶段的接口自动化测试。
1.5 Selenium 工具介绍
Selenium IDE是嵌入到Firefox浏览器中的一个插件,实现简单的浏览器操作的录制和回放功能。主要应用是快速创建bug重现脚本,在测试人员的测试过程中,发现了Bug之后可以通过IDE将重现的步骤录制下来,以帮助开发人员更容易的重现BUG.
Selenium Grid:是一种自动化的测试辅助工具,Grid通过利用现有的计算机基础设施,能加快web-app的功能测试。利用Grid,可以很方便地同时在多台机器上和异构环境中并行运行多个测试实例。其特点是:
1. 并行执行
2. 通过一个主机统一控制用例在不同环境、不同浏览器下运行
3. 灵活添加变动测试机
Selenium RC:支持多种不同的语言编写自动化测试脚本,通过Selenium RC的服务器作为代理服务器去访问应用从而达到测试的目的。Selenium RC 使用分 Client Libraries 和 Selenium Server,Client Libraries 库主要用于编写测试脚本,用来控制Selenium Server的库。Selenium Server 负责控制浏览器行为,总的来说,Selenium Server 主要包括3 个部分:Launcher、Http Proxy、Core。其中Selenium Core 是被Selenium Server 嵌入到浏览器页面中的。其实Selenium Core
就是一堆JS 函数的集合,就是通过这些JS 函数,我们才可以实现用程序对浏览器进行操作。Launcher 用于启动浏览器,把selnium Core 加载到浏览器页面当中,并把浏览器的代理设置为SeleniumServer 的Http Proxy。
1.6 前端工具
FireBug:集HTML查看和编辑、Javascript 控制台、网络状况监视器、cookie 查看于一体,是开发JavaScript、CSS、HTML和Ajax 的得力助手。
2.1.1 安装 Python
访问Python 官方网站:https://www.Python.org/
2.1.2 安装steuptools 与pip
setuptools 与pip 下载地址:
https://pypi.Python.org/pypi/setuptools
https://pypi.Python.org/pypi/pip
通过解压工具进行解压将得到两个文件夹,在Windows 命令提示符进入到文件解压目录,通过Python执行安装文件setup.py 进行安装。安装setuptools:
C:\package\setuptools-7.0>Pythonsetup.py install
安装pip 的方法与setuptools 相同,切换到pip 解压目录,运行setup.py 文件:
C:\package\pip-1.5.6>Pythonsetup.py install
2.1.4ActivePython
访问ActivePython 下载地址:
http://www.activestate.com/activePython/downloads
2.2 编写第一个脚本
baidu.py
#codiong=uft-8
from selenium import webdriver
driver=webdriver.Chrom()
driver.get(“http://www.baidu.com”)
driver.find_element_by_id(“kw”).send_keys(“Selenium2”)
driver.find_element_by_id(“su”).Click()
driver.quit()
Python 提供print方法来打印信息:print “hello”
调用print方法,用户双引号(“ ”)把需要打印的信息引起来就被输出了。
>>>name=”zhangsan”
>>>print “hello %s,Nice tomeet you!” %name
%s(string)只能打印字符串,如果想打印数字,那么就要使用%d(data)
>>>age=27
>>>print “You are %d !” %age
如果不知道自己要打印的是什么类型的数据,那么可以用%r来表示
>>> n=100
>>>print “Youprint is %r .” %n
>>> n=”abc”
>>>print “Youprint is %r .” %n
Python提供input输入:
#coding=utf-8
n=input(“Enter any content:”)
print “Your input is %r ”%n
但是input()方法比较矫情,要求用户输入的数据类型一定正确,比如字符串一定要加引号,如果不加会报错。
我们可以使用raw_input()方法,用户输入什么就是什么。
在Python当中,不区分单引号(‘ ’)与双引号(“ ”),单双引号都可以表示一个字符串
>>>print “hello”
>>>print ‘world’
可以嵌套使用,但不能交叉使用。
Python的单注释用井号(#)表示。
多行注释用三对引号表示,不分单、双引号。
分支一般就用if..else..语句,循环一般就用for语句。Xx.py
Results=72
If Results>=90:
Print u’优秀’
Elif Results>=70:
Print u’良好’
Elif Results>=60:
Print u’及格’
Else:
Print u’不及格’
For 语句:循环一个字符串的每一个字符。
Strings=“hello world”
For I in strings:
Print I
循环数字,循环数字要借助range()函数。
For I in range(1,10):
Print I
range(start,end,scan):start表示开始的位置,end表示结束的位置,scan表示每一次循环的步长。
数组用中括号[]表示,里面的每一个元素用逗号(,)隔开。数组下标从0开始的。
>>>shuzu=[1,2,3,’a’,5]
>>>print shuzu
>>>print shuzu[0]
>>>printshuzu[4]
字典以花括号{}表示,里面的元素是成对出现的,一个key对应一个value;一对元素用冒号(:)分割;不同元素用逗号(,)分开。
>>>zidian={“username”:”password”,’man’:’woman’,1:2}
>>>zidian.keys()
>>>zidian.values()
>>>zidian.items()
字典里的每一对元素准确的来说是键值对,一个键(key)对应一个值(value)。Keys()函数可以输出所有键的值;values()函数可以输出所有值的值;items()函数输出一对键值对的值。
3.4.1函数
在python当中通过def关键字来定义函数,下面来定义一个函数:
>>>def add(a,b):
printa+b
>>>add(3,5)
创建一个add(),这个函数接收两个参数,a,b,通过print打印a+b的结果。通常情况下,函数不会直接答应结果,而是将处理结果通过return关键字返回。
>>>def add(a,b):
return a+b
>>>add(3,5)
有时候调用add()函数的时候不想传参,可以为函数设置默认参数。
>>>def add(a=6,b=7):
returna+b
>>>add()
>>>add(5,8)
3.4.2 类与方法
在Python中用class关键字来创建类。
Demo.py
Class A():
Defadd(self,a,b):
Returnself.a+self.b
Count=A()
Print count.add(3,5)
创建了一个A()类,在类下面创建了一个add()方法。方法创建同样适用关键字def,唯一不同的是方法必须有一个且必须是第一默认参数self,但是这个参数不用传值。
XX.py
Class A():
Defadd(self,a,b):
Returna+b
Class B(A):
Defsub(self,a,b):
Returna-b
Count=B()
Print count.add(4,5)
用count变量来等于B类,因为B类继承了A类,所以B类也拥有了add()方法,所以count可以调用add()方法
3.5.1 引用模块
在Python语言中通过from..import..的方式引用模块,下面引用time模块。
XX.PY
Import time
Print time.ctime()
如果只用到time模块下面的ctime()方法,可以这样使用:
Xx.py
From time import ctime
Print ctime()
一次性把time模块下面的所有方法都引进来:
Xx.py
#coding=utf-8
From time import *
Print ctime()
Print “休息一两秒”
Sleep(2)
Python 所安装的模块存放在C:\Python27\Lib\site-packages\目录下面
3.5.2 模块调用
我们可以自己创建一个模块,然后通过另一个程序调用。
创建一个目录(project),在目录下面创建一个文件(pub.py),在文件中创建一个函数。
Project\pub.py
Def add(a,b):
Print a+b
在相同的目录下面创建一个文件(count.py)
Project\count.py
Import pub
Printpub.add(3,5)
这样就实现了跨文件的函数调用。
**知识延伸:
在project目录下面多了一个pub.pyc文件,pyc文件是一种二进制文件,是由py文件经过编译后,生成的文件,是一种byte code,py文件变成pyc文件后,加载的速度有所提高,而且pyc是一种跨平台的字节码,是由python的虚拟机来执行。
3.5.3 跨目录模块调用
调用文件和被调用的文件不在同一目录下面,调用目录如下:
----project/model/pub.py
----project/count.py
Ps:删除刚才调用生成的pub.pyc文件。再来执行count.py,python会给出提示信息,找不到pub模块。那么python是如何找到模块的呢?
首先要知道,python在执行import语句时,到底进行了什么操作,按python的文档,它执行如下操作:
第一步,创建一个新的,空的module对象(它可能包含多个module)
第二步,把这个module对象插入sys.module中
第三步,装载module的代码(如果需要,首先必须编译)
第四步,执行新的module中对应的代码
在执行第三步时,首先要找到,module程序所在的位置,搜索顺序是:
当前路径(以及从当前目录指定的sys.path),然后是pythonPATH,然后是python的安装设置相关的默认路径。正因为这样的顺序,如果当前路径或pythoPATH中存在与标准module同样module,则会覆盖标准module。也就是说,如果当前目录下存在XML.py,那么执行import XML时,导入的是当前目录下的module,而不是系统标准的XML。
我们可以先构建一个package,以普通的方式导入,就可以直接访问此package中各个module了。在python中的package必须包含一个__init__.PY的文件.
现在我们就可以将..project/model/目录添加到系统环境变量下的path下面,但是这样不够灵活,我们可以调用python的sys模块来实现。
Project\count.py
Import sys
Sys.path.append(‘\model’)
From model import pub
Print pub.add(3,5)
调用sys模块,把model目录通过append()方法追加到系统环境变量path下面。Append()是一个非常有用的方法,它通常用于向一个数据或集合尾部添加新数据。
PS:”\model”是一个相对路径,如果pub.py在别的目录下面,就需要用绝对路径了,如:append(“D:\\project\\model”)
现在运行程序依然会告诉我们找不到model,我们还需要在model目录下面创建一个__init__.PY的文件,内容可以为空。这个文件告诉python model是一个可以被调用的模块。现在就可以正常运行了。
那么我们可以在__init__.PY的文件目录下面放点什么呢?例如在model目录下面有两三个文件(a.py、b.py、c.py),那么打开__init__.PY的文件:
Import a,b
Project\count.py
Import sys
Sys.path.append(‘model’)
From model import *
Print pub.add(2,3)
现在我们用星号(*)表示导入model 下面所有文件,这个所有具体包含什么由__init__.py 决定,因为只import 了a 和b 了.
Python用异常对象(exception object来表示异常情况。遇到错误后,会引发异常。如果异常对象未被处理或捕捉,程序会用所谓的回溯(Traceback,一种错误信息)终止执行。
Python提供try..except..语句来接收这个异常。
在python中所有的异常都继承Exception,所以我们可以使用它来接收所有的异常。
Abnormal.py
Try:
Open(“abc.txt”,”r”)
Printaa
Except Exception:
Print “异常了”
从python2.5版本之后,所有异常类有了新的基类BaseException,Exception同样也继承BaseException,所以我们也可以使用BaseException来接收所有的异常。
Python直接输出异常信息:
Abnormal.py
Try:
Open(“abc.txt”,”r”)
Printaa
Except BaseException,msg:
Print msg
在BaseException后面定义msg变量用于接收异常信息,通过print将其打印出来:
Python中常见的异常:
BaseException 新的所有异常类的基类
Exception 所有异常类的基类,但继承BaseException 类
AssertionError assert 语句失败
AttributeError 试图访问一个对象没有属性
IOError 输入输出异常,试图打一个不存的文件(包括其它情况)时引起
NameError 使用一个还未赋值对象的变量
IndexError 在使用序列中不存在的所引进引发
IndentationError 语法错误,代码没有正确的对齐
KeyboardInterrupt Ctrl+C 被按下,程序被强行终止
TypeError 传入的对象类型与要求不符
SyntaxError Python 代码逻辑语法出错,不能执行
3.6.2更多异常用法
try...except 与else 配合使用:
Abnormal.py
Try:
Open(“abc.txt”,”r”)
Printaa
Except BaseException,msg:
Print msg
Else:
Print ‘没有异常!’
Else语句只有在没有异常的情况下才会被执行,但是有些情况下不管是否出现异常这些操作都能被执行,比如文件的关闭,所得释放,把数据库连接返还给连接池等操作。我们可以使用Try…finally..语句来完成。
首先创建一个poem.txt文件:
Pome.txt
ABC
EFG
HIJK
LMN
OPQ
通过一个小程序来读取文件中的内容。
ReadFile.py
#coding=utf-8
Import time
Files=file(“poem.txt”,”r”)
Strs=Files.readlines()
Try:
For I in strs:
Print I
Time.sleep(1)
Finally:
Files.close()
Print “Clean up…closed the file”
3.6.3抛出异常
Python中提供raise方法来抛出一个异常:Abnormal.py
Filename=raw_input(‘please input filename:’)
If filename==’hello’:
Raise NameError(‘input file name error!’)
在Python语言中对应的定位方法如下:
find_element_by_id()
find_element_by_name()
find_element_by_class_name()
find_element_by_tag_name()
find_element_by_link_text()
find_element_by_partial_link_text()
find_element_by_xpath()
find_element_by_css_selector()
用by定位元素,find_element()方法只用于定位元素。它需要两个参数,第一个参数是定位方式,这个由By提供;第二个参数是定位的值。在使用By时需要将By类导入。
from selenium.webdriver.common.by import By
WebDriver提供了set_window_size()方法来设置浏览器的大小。
Test.py
#coding=utf-8
From selenium import webdriver
Driver=webdriver.Chorm()
Driver.get(“http://m.mail.10086.cn”)
Print “设置浏览器的宽480,高800显示”
Driver.set_window_size(480,800)
Driver.quit()
Maximize_window()是浏览器最大化
WebDriver提供back()和forward()方法来模拟后退和前进。
Test.py
#coding=utf-8
From selenium import webdriver
Driver=webdriver.Chrome()
Firt_url=http://www.baidu.com
Print “now access %r” %first_url
Driver.get(first_url)
Second_url=http://news.baidu.com
Print “now access %s” %second_url
Driver.get(second_url)
Print “back to %s” %(first_url)
Driver.back()
Print “forward to %s” % second_url
Driver.forward()
Driver.quit()
在WebDriver中,大多简单有趣的页面交互的方法都将通过WebElement接口提供,最常用的操作页面元素的方法如下:
Clear() 清除文本,如果是一个文本输入框
Send_keys(*value)在元素上模拟按键输入
Click() 单击元素
Login163.py
#coding=utf-8
From seleniumimport webdriver
Driver=webdriver.Chrome()
Driver.get(“http://www.126.com”)
Driver.find_element_by_id(“idInput”).clear()
Driver.find_element_by_id(“idInput”).send_keys(“username”)
Driver.find_element_by_id(“pwdInput”).clear()
Driver.find_element_by_id(“pwdInput”).send_keys(“password”)
Driver.find_element_by_id(“loginBtn”).click()
Driver.close()
Click()方法和send_keys()方法是web页面操作中最常用到的两个方法。
Click()方法不仅仅用于点击按钮,还可以单击任何可以点击文字/图片链接、复选框、单选框、甚至是下拉框等。
Submit()方法用于提交表单,这里特别用于没提交按钮的情况,例如输入关键字之后的“回车”操作,那么就可以通过submit()来提交搜索框的内容。
Youdao.py
#coding=utf-8
From seleniumimport webdriver
Driver=webdriver.Chrome()
Dirver.get(“http://www.youdao.com”)
Driver.find_element_by_id(“query”).send_keys(“hello”)
Driver.find_element_by_id(“query”).submit()
Driver.quit()
有时候submit()可以和click()方法互换使用,submit()同样可以提交一个按钮。
Size 返回元素的尺寸
Text 获取元素的文本
Get_attribute(name) 获取属性值
Is_displayed() 设置该元素是否用户可见。
Baidu.py
#coding=utf-8
From seleniumimport webdriver
Driver=webdriver.Chrome()
Driver.get(“http://www.baidu.com”)
Size=driver.find_element_by_id(“kw”).size
Print “kwelement size is %d” %size
Text=driver.find_element_by_id(“cp”).text
Print “cpelement text is %r” %text
Attribute=driver.find_element_by_id(“kw”).get_attribute(“type”)
Print “The typeattribute of kw element is %r” %attribut
Result=driver.find_element_by_id(“kw”).is_displayed()
Driver.close()
在webdriver中这些关于鼠标操作的方法由ActionChains类提供。
ActionChains类提供的鼠标操作的常用方法:
l Perform() 执行所有ActionChains()中存储的行为
l Context_click() 右击
l Double_click() 双击
l Drag_and_drop() 拖动
l Move_to_element() 鼠标悬停
鼠标右击操作:xx.py
#conding=utf-8
From seleniumimport webdriver
Fromselenium.webdriver.common.action_chains import ActionChains
Driver=webdrive.Chrome()
Driver.get(“http://yun.baidu.com/”)
Driver.find_element_by_id(“TANGRAM__PSP_4__userName”).clear()
Driver.find_element_by_id(“TANGRAM__PSP_4__userName”).send_keys(“username”)
Driver.find_element_by_id(“TANGRAM__PSP_4__password”).clear()
Driver.find_element_by_id(“TANGRAM__PSP_4__password”).send_keys(“password”)
Driver.find_element_by_id(“TANGRAM__PSP_4__submit”).click()
Disk_NET=driver.find_element_by_class_name(“pulldown-nav”)
ActionChains(driver).move_to_element(Disk_NET)
DC=driver.find_element_by_class_name(“li disk”)
ActionChains(driver).double_click(DC)
(未完待续)
Drag_and_drop(source,target):在原元素上按下鼠标左键,然后移动到目标元素上释放
Keys类提供键盘上几乎所有的按键的方法,send_keys()方法可以模拟键盘输入,除此之外还可以模拟键盘上的一些组合键,例如Ctrl+A,Ctrl+C等
KEYS.py
#coding=utf-8
From selenium import webdriver
From selenium.webdriver.commom.keys import Keys
Driver=webdriver.Chrome()
Driver.get(“http://www.baidu.com”)
Driver.find_element_by_id(“kw”).send_keys(“seleniumm”)
#删除多输入的一个m
Driver.find_element_by_id(“kw”).send_keys(Keys.BACK_SPACE)
#Ctrl+a全选输入框内容
Driver.find_element_by_id(“kw”).send_keys(Keys.CONTROL,’a’)
#Ctrl+x全选输入框内容
Driver.find_element_by_id(“kw”).send_keys(Keys.CONTROL,’x’)
#Ctrl+v全选输入框内容
Driver.find_element_by_id(“kw”).send_keys(Keys.CONTROL,’v’)
Driver.find_element_by_id(“su”).send_keys(Keys.ENTER)
Driver.close()
导入键盘类包:From selenium.webdriver.commom.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