除了selenium自动化 还有好用的网页自动化工具吗

1 什么是selenium
Selenium 是一个基于浏览器的自动化工具,它提供了一种跨平台、跨浏览器的端到端的web自动化解决方案。Selenium主要包括三部分:Selenium IDE、Selenium WebDriver 和Selenium Grid:
Selenium IDE:Firefox的一个扩展,它可以进行录制回放,并可以把录制的操作以多种语言(例如java,python等)的形式导出成测试用例。
Selenium WebDriver:提供Web自动化所需的API,主要用作浏览器控制、页面元素选择和调试。不同的浏览器需要不同的WebDriver。
Selenium Grid:提供了在不同机器的不同浏览器上运行selenium测试的能力
本文中主要使用python结合Selenium WebDriver库进行自动化测试框架的搭建。
2 自动化测试框架
一个典型的自动化测试框架一般包括用例管理模块、自动化执行控制器、报表生成模块和日志模块等,这些模块之间不是相互孤立的,而是相辅相成的。
下面来介绍下每个模块的逻辑单元:
用例管理模块
用例管理模块包括用例的添加、修改、删除等操作单元,这些单元也会涉及到用例书写的模式,测试数据的管理、可复用库等
自动化执行控制器
控制器是自动化用例执行的组织模块,主要负责以什么方式去执行用例。比较典型的控制器有用户图形界面(GUI)和&commandline+文件&两种。
报表生成模块
报表生成模块主要负责执行完用例以后生成报表,报表一般以HTML格式居多,信息主要包括用例的执行情况及相应的总结报告。另外还可以添加发送邮件功能。
日志模块主要用来记录用例的执行情况,以便于更高效的调查用例失败信息及追踪用例执行情况。
3 自动化框架的设计与实现
3.1&&&&&& 需求分析
测试对象是一个典型的后台系统的Web展现平台,基于此平台设计的自动化框架要包含测试用例管理、测试执行控制、测试报表及测试日志的生成,整体测试框架要轻量易用。
3.2&&&&&& 概要设计
概要设计包括了四个大的模块:公共库模块(可复用函数、日志管理、报表管理以及发送邮件管理)、用例仓库(具体用例的管理)、页面管理(单独对Web页面进行抽象,封装页面元素和操作方法)以及执行模块。
概要设计类图:
3.3&&&&&& 详细设计与实现
3.3.1&&&&&&& 页面管理
&&&&&&&&&&&&&&& 测试Web对象是一个典型的单页面应用,因此采用页面模式(page pattern)来进行组织:
页面模式是页面与测试用例之间的桥梁,它将每个页面抽象成一个单独的页面类,为测试用例提供页面元素的定位和操作。
页面模式的类图如下:
BasePage作为基类只包含一个driver成员变量,它用来标记Selenium中的WebDriver,以便在BasePage的派生类中定位页面元素。LoginPage和PageN等作为派生类,可以提供相应页面元素的定位和操作方法。比如测试对象的登录页面:
从页面可以看出,需要操作的页面元素分别为:Username,Password,remember my username checkbox和Sign in按钮,它们对应的操作为输入用户名和密码,点选checkbox和点击Sign In按钮,具体代码级别的实现如下:
页面基类BasePage.py:
class BasePage(object):
"""description of class"""
#webdriver instance
def __init__(self, driver):
self.driver = driver
LoginPage页面继承自BasePage,并进行Login Page的元素定位及操作实现。代码中定位了username和password,并且添加了设置用户名和密码的操作。
from BasePage import BasePage
from mon.by import By
from mon.keys import Keys
class LoginPage(BasePage):
"""description of class"""
#page element identifier
usename = (By.ID,'username')
password = (By.ID, 'password')
dialogTitle = (By.XPATH,"//h3[@class=\"modal-title ng-binding\"]")
cancelButton = (By.XPATH,'//button[@class=\"btn btn-warning ng-binding\"][@ng-click=\"cancel()\"]')
okButton = (By.XPATH,'//button[@class=\"btn btn-primary ng-binding\"][@ng-click=\"ok()\"]')
#Get username textbox and input username
def set_username(self,username):
name = self.driver.find_element(*LoginPage.usename)
name.send_keys(username)
#Get password textbox and input password, then hit return
def set_password(self, password):
pwd = self.driver.find_element(*LoginPage.password)
pwd.send_keys(password + Keys.RETURN)
#Get pop up dialog title
def get_DiaglogTitle(self):
digTitle = self.driver.find_element(*LoginPage.dialogTitle)
return digTitle.text
#Get "cancel" button and then click
def click_cancel(self):
cancelbtn = self.driver.find_element(*LoginPage.cancelButton)
cancelbtn.click()
#click Sign in
def click_SignIn(self):
okbtn = self.driver.find_element(*LoginPage.okButton)
okbtn.click()
采用页面模式来管理页面和测试用例有很多好处,主要体现在:
简单并且清晰
每个页面都有单独的类来封装页面元素和操作,让页面操作更加具体化,而不是相对独立的。
比如未使用页面模式,测试用例的输入用户名和密码的代码:
#enter username and password
driver.find_element_by_id("username").clear()
driver.find_element_by_id("username").send_keys("sbxadmin")
driver.find_element_by_id("password").clear()
driver.find_element_by_id("password").send_keys("password"+Keys.RETURN)
使用页面模式之后,输入用户名和密码的代码:
#Step2: Open Login page
login_page = BasePage.LoginPage(self.driver)
#Step3: Enter username
login_page.set_username("username")
#Step4: Enter password
login_page.set_password("password")
通过对比我们不难发现,未使用页面模式的代码组织比较混乱,步骤多,可读性非常差,不难想象,一个通篇都是find_element_by_id或者send_Keys的测试用例到底有多糟糕!而使用了页面模式之后,在哪个页面做什么操作都非常清晰,非常接近测试用例的步骤,易读性非常好。
可复用性好
由于页面操作都被封装在了页面类中,所以页面方法和容易调用,可复用性非常好。而未使用页面模式的用例只能每次都实现一遍。
可维护性好
由于测试目标页面的多变性,页面元素的定位经常需要改变,利用了页面模式后,只需要修改一遍其页面类中的定位就可以对所用用到该元素的测试用例生效;而在未使用该模式的情况下,必须修改每一个用到该元素的测试用例,非常容易遗漏,工作量也非常大。
综合以上页面模式的各种优点,我们在以后的web自动化中可以多使用该模式来组织页面。
3.3.2&&&&&&& 公共库模块
&&&&&&&&&&&&&&& 公共库模块是为创建测试用例服务的,它主要包括常量、公共函数、日志管理、报表管理以及发送邮件管理等。
&&&&&&&&&&&&&&& 公共库模块涉及到的功能一般多而杂,在设计的时候只要遵循高内聚低耦合就可以了。比如常量、变量和一些公共函数可以放在同一个文件中Common.py:
from datetime import datetime
def driverPath():
return r'C:\Users\xua\Downloads\chromedriver_win32\chromedriver.exe'
def baseUrl():
return "https://xxx.xxx.xxx.xxx:9000"
#change time to str
def getCurrentTime():
format = "%a %b %d %H:%M:%S %Y"
return datetime.now().strftime(format)
# Get time diff
def timeDiff(starttime,endtime):
format = "%a %b %d %H:%M:%S %Y"
return datetime.strptime(endtime,format) - datetime.strptime(starttime,format)
测试用例信息类用来标识测试用例,并且包括执行用例执行结果信息,主要包括以下字段:
class TestCaseInfo(object):
"""description of class"""
def __init__(self, id="",name="",owner="",result="Failed",starttime="",endtime="",secondsDuration="",errorinfo=""):
self.id = id
self.name = name
self.owner = owner
self.result = result
self.starttime = starttime
self.endtime = endtime
self.secondsDuration = secondsDuration
self.errorinfo = errorinfo
测试用例信息需要在每个测试用例中实例化,以便对测试用例进行标记,并最终体现在测试报告中。
日志主要用来记录测试用例执行步骤及产生的错误信息,不同的信息有不同的日志级别,比如Information,Warning,Critical和Debug。由于每个测试用例产生的日志条目比较少,所以在测试框架中只利用了最高级别的日志打印,即Debug级别,该级别也会将其他所有的日志级别的信息同样打印出来。在具体的实现中引用了Python标准库中的logging类库,以便更方便的控制日志输出:
import logging
import ResultFolder
logger = logging.getLogger()
logger.setLevel(logging.DEBUG)
def CreateLoggerFile(filename):
fulllogname = ResultFolder.GetRunDirectory()+"\\"+filename+".log"
fh = logging.FileHandler(fulllogname)
fh.setLevel(logging.DEBUG)
formatter = logging.Formatter('%(asctime)s [line:%(lineno)d] %(message)s')
fh.setFormatter(formatter)
logger.addHandler(fh)
except Exception as err:
logger.debug("Error when creating log file, error message: {}".format(str(err)))
def Log(message):
logger.debug(message)
报表管理及发送邮件模块实现了报表(html格式)的生成及自动发送邮件的功能。报表和邮件依附于当前测试的执行,每次执行都会独立的触发报表生成和邮件发送。该模块主要运用了Python中的lxml、smtplib和email库。
3.3.3&&&&&&& 用例仓库
&&&&&&&&&&&&&&& 用例仓库主要用来组织自动化测试用例。每条测试用例都被抽象成一个独立的类,并且均继承自unittest.TestCase类。 Python中的unittest库提供了丰富的测试框架支持,包括测试用例的setUp和tearDown方法,在实现用例的过程中可以重写。依托页面管理和公共库模块实现的页面方法和公共函数,每一个测试用例脚本的书写都会非常清晰简洁,一个简单的Floor Manager Lite的登录用例如下:&&
class Test_TC_Login(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Chrome(cc.driverPath())
self.base_url = cc.baseUrl()
self.testCaseInfo = TestCaseInfo(id=1,name="Test case name",owner='xua')
self.testResult = TestReport()
LogUtility.CreateLoggerFile("Test_TC_Login")
def test_A(self):
self.testCaseInfo.starttime = cc.getCurrentTime()
#Step1: open base site
LogUtility.Log("Open Base site"+self.base_url)
self.driver.get(self.base_url)
#Step2: Open Login page
login_page = LoginPage(self.driver)
#Step3: Enter username & password
LogUtility.Log("Login web using username")
login_page.set_username("username")
login_page.set_password("password")
time.sleep(2)
#Checkpoint1: Check popup dialog title
LogUtility.Log("Check whether sign in dialog exists or not")
self.assertEqual(login_page.get_DiaglogTitle(),"Sign in")
#time.sleep(3)
#Step4: Cancel dialog
login_page.click_cancel()
self.testCaseInfo.result = "Pass"
except Exception as err:
self.testCaseInfo.errorinfo = str(err)
LogUtility.Log(("Got error: "+str(err)))
self.testCaseInfo.endtime = cc.getCurrentTime()
self.testCaseInfo.secondsDuration = cc.timeDiff(self.testCaseInfo.starttime,self.testCaseInfo.endtime)
def tearDown(self):
self.driver.close()
self.testResult.WriteHTML(self.testCaseInfo)
if __name__ == '__main__':
unittest.main()
从这个测试用例中,我们可以看到
Setup中定义了执行测试用例前的一些实例化工作
tearDown对执行完测试做了清理和写日志文件工作
测试步骤、测试数据和测试检查点非常清晰,易修改(比如用户名密码)
日志级别仅有Debug,所以写日志仅需用同一Log方法
3.3.4&&&&&&& 用例执行模块(控制器)
&&&&&&&&&&&&&&& 执行模块主要用来控制测试用例脚本的批量执行,形成一个测试集。用例的执行引用了Python标准库中的subprocess来执行nosetests的shell命令,从而执行给定测试用例集中的用例。测试用例集是一个简单的纯文本文件,实现过程中利用了.txt文件testcases.txt:
Test_Login_pass.py
Test_Login_Fail.py
#Test_MainPage_CheckSecurityTableInfo.py
Test_MainPage_EditSecurityInfo.py
用例前没有&#&标记的测试用例脚本会被执行,而有&#&标记的则会被忽略,这样可以很方便的控制测试集的执行,当然也可以创建不同的文件来执行不同的测试集。
具体的调用代码如下:
def LoadAndRunTestCases(self):
f = open(self.testcaselistfile)
testfiles = [test for test in f.readlines() if not test.startswith("#")]
for item in testfiles:
subprocess.call("nosetests "+str(item).replace("\\n",""),shell = True)
except Exception as err:
LogUtility.logger.debug("Failed running test cases, error message: {}".format(str(err)))
EmailUtils.send_report()
3.4&&&&&& 执行结果
测试用例执行完毕后主要有两种输出:日志和测试报告。测试报告会html附件的形式通过邮件发出,例如:
4 需要改进的模块
& & &对于现有实现的测试框架,已经可以满足web对象的自动化需求,但还是有些可以改进提高的地方,比如:
针对部分测试用例是否可以尝试数据驱动
添加屏幕截图功能
封装selenium中By库中的函数,以便更高效的定位页面元素等
结合业界优秀的自动化框架和实践持续改进
& & & & &基于selenium实现的web自动化框架不仅轻量级而且灵活,可以快速的开发自动化测试用例。结合本篇中的框架设计以及一些好的实践,希望对大家以后的web自动化框架的设计和实现有所帮助。
源代码:/AlvinXuCH/WebAutomaiton&
阅读(...) 评论()Posts - 264,
Articles - 1,
Comments - 2346
大人不华,君子务实。
独立博客:
21:15 by 虫师, ... 阅读,
Selenium&并不像那样让人一下子就明白是什么?它是编程人员的最爱,但它却对测试新手产生了很大的阻碍。
Selenium&是啥?
Selenium&RC是啥?
Webdriver&又是啥?
RC&和&是啥关系?
Webdriver&和编程语言啥关系?
Selenium&能并行执行脚本嘛?
Selenium&能做移动端自动化么?
这里虫师用简单方式,告诉你,他们错综复杂的关系。理顺了它们之间的关系才能真正使用它。
Selenium&是什么?
Selenium&是自动化测试工具集,包括、、()、()等。
Selenium&IDE&是浏览器的一个插件。提供简单的脚本录制、编辑与回放功能。
Selenium&Grid&是用来对测试脚步做分布式处理。现在已经集成到中了。
RC和更多应该把它看成一套规范,在这套规范里定义客户端脚步与浏览器交互的协议。以及元素定位与操作的接口。
WebDriver是什么?
对于刚接触自动化测试的同学来说不太容易理解是什么,它到底和编程语言之是什么关系。
当初,在刚学selenium&(webdriver)的时候花了一个星期来翻译这个文档,后来也没弄明白,它是啥。其实它就是一层基础的协议规范。
假如说:Webdriver&API(接口规范)说,我们要提供一个页面元素id的定位方法。
Ruby的webdriver模块是这么实现的:
require "selenium-webdriver"
#导入ruby版的selenium(webdriver)
find_element(:id,&"xx")
#id定位方法
C#的webdriver模块是这么实现的:
using OpenQA.S
using OpenQA.Selenium.F
//导入C#版的selenium(webdriver)
FindElement(By.Id("xx"))
//id定位方法
python的webdriver模块是这么实现的:
selenium import webdriver
#导入python版的selenium(webdriver)
find_element_by_id("xx")
#id定位方法
Java的模块是这么实现的:
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxD//导入java版的selenium(webdriver)
findElement(By.id("xx"))
//id定位方法
&因为对于底层过于封装,所以,我们看不到语言层面的方法定义。所以,提供给我们的方法如下:
1、导入版本的()
2、使用方法
Click&element
需要说明的是&只提供了页面操作的相关规范,比如元素定位方法,浏览器操作,获取页元素属性等。
Webdriver&&如何组织和执行用例?
&&&&对不起,不会。
把写好这些操作页面元素的方法(用例)组织起来执行并输入测试结果,是由编程语言的单元测试框架去完成的。如的和单元测试框架,的单元测试框架等。
Selenium&RC&和什么关系?
RC和&类似,都可以看做是一套操作页面的规范。当然,他们的工作原理不一样。
selenium&RC&在浏览器中运行&应用,使用浏览器内置的&翻译器来翻译和执行命令(是&命令集合)&。
WebDriver&通过原生浏览器支持或者浏览器扩展直接控制浏览器。针对各个浏览器而开发,取代了嵌入到被测&应用中的&。与浏览器的紧密集成支持创建更高级的测试,避免了安全模型导致的限制。除了来自浏览器厂商的支持,还利用操作系统级的调用模拟用户输入。
看样子更牛一些。为了保持向兼容,所以中,和并存,但说起一般指的是。
并行与分布式的区别
有同学好奇如何并行的执行测试用例,并行要求&同时&执行多条用例,这个也是由编程语言的多线程技术实现的。
你会问不是可以实现分布式执行么?&分布式的概念是写好一条用例可以调用不同的平台执行,如&电脑上有一个测试用例,可以调用电脑()的&浏览器来跑电脑上的测试用例;也可以调用电脑()的&浏览器来跑电脑上的测试用例。这是分布式的概念。
Selenium如何能做移动端测试么?
这里我们以语言为例。
from selenium import webdriver
driver= webdriver.Chrome()
#获取浏览器驱动。拿到浏览器驱动driver 才能操作浏览器所打找的页面上的元素。
我们把驱动展开是这样的
from selenium import webdriver
driver = webdriver.Remote(
command_executor='http://127.0.0.1:4444/wd/hub',
desired_capabilities={'platform': 'ANY',
'browserName':chrome,
'version': '',
'javascriptEnabled': True
驱动里包含了一些参数,代理服务器()平台,浏览器&浏览器版本等。
移动端的自动化测试工具A
从本质上来讲,同样继承了的接口规范。同样是支持多种编程语言的。这里仍然以为例子。
from appium import webdriver
#导入python版的 appium(webdriver)模块
#定义驱动的参数
desired_caps = {}
desired_caps['platformName'] = 'Android'
desired_caps['platformVersion'] = '4.2'
desired_caps['deviceName'] = 'Android Emulator'
desired_caps['appPackage'] = 'com.android.calculator2'
desired_caps['appActivity'] = '.Calculator'
driver = webdriver.Remote('http://localhost:4723/wd/hub', desired_caps)
这一次因为我们操作的是移动端的安卓。所以我们驱动的参数里就要指定平台是版本是等信息。拿到驱动后,就可以操作安卓上的了。微信公众号
Selenium一个强大的基于浏览器的开源自动化测试工具
追踪溯源,WebDriver 和 Selenium 本是两个独立的项目,实现机制也是不同的。那 Selenium 团队为什么会在 Selenium 2 中将两者合并,这究竟有什么用意呢?WebDriver 比 Selenium 又有什么优势呢?我们该如何选择使用 Selenium 还是 WebDriver 呢?别着急,您将在本文中找到答案,并将了解一些 WebDriver 的基本知识和使用方法。
为方便表述,在本文中,我们称 Selenium 2 为 WebDirver,Selenium 为 Selenium 1.x(因为 Selenium1.x 时通常指的是 Selenium RC,所以 Selenium 也指 Selenium RC)。
WebDriver 是& &?
Selenium 2,又名 WebDriver,它的主要新功能是集成了 Selenium 1.0 以及 WebDriver​(WebDriver 曾经是 Selenium 的竞争对手)。也就是说 Selenium 2 是 Selenium 和 WebDriver 两个项目的合并,即 Selenium 2 兼容 Selenium,它既支持 Selenium API 也支持 WebDriver API。
那 Selenium 团队为什么会将两个项目合并呢?我们通常认为其中部分原因是 WebDriver 解决了 Selenium 存在的缺点(比如,能够绕过 JS 沙箱),部分原因是 Selenium 解决了 WebDriver 存在的问题(比如,支持更广泛的浏览器和编程语言),不论真正的原因是什么两个项目的合并为用户提供了一个优秀的自动化测试框架。
现在让我们看看两个工具有什么具体的不同。在开始之前,我们首先看一下用 Selenium 和用 Webdriver 构建出来的测试工程是什么样的,后文会在这个基础上阐述 Webdriver 和 Selenium 的异同。
说明:因为现在 WebDriver 还在改进和优化过程中,所以我们以下的举例和说明都是基于版本 selenium-2.28.0 的基础上。
构建一个 Selenium 测试工程
Selenium&API 则支持更多的编程语言,这里我们还是以 Java 为例。
图 1. Selenium 测试工程
清单 1. 使用 Selenium API 的脚本 - 登录 SmartCloud iNotes
import com.thoughtworks.selenium.DefaultS
import com.thoughtworks.selenium.S
public class SeleniumDemo {
public static void main(String[] args) throws InterruptedException {
// 创建一个 Selenium 实例
Selenium selenium = new DefaultSelenium(&localhost&, 4444, \
&*firefox&, &https://apps./&);
// 启动 selenium session
selenium.start();
// 打开测试网页
selenium.open(&/&);
// 输入用户名,密码
selenium.type(&//input[@id='username']&, \
&autouser01@e3yunmail.&);
selenium.type(&//input[@id='password']&, &test&);
selenium.click(&//input[@id='submit_form']&);
// 等待直到页面出现 Mail 链接
int count = 60;
while(count & 0){
if(selenium.isElementPresent(&//a[contains(text(),'Mail')]&)){
Thread.sleep(1000);
selenium.click(&//a[contains(text(),'Log Out')]&);
// 测试结束后,终止 selenium session
selenium.stop();
其他类似的新闻
● ● ● ● ● ● ● ● ● ●
其他相关的新闻
大家感兴趣的内容
小伙伴最爱的新闻
小伙伴还关注了以下信息
小伙伴关注的焦点
小伙伴都在关注的热门词
Copyright (C) 2006- Inc. All Rights Reserved
孝感风信信息技术有限公司 ● 版权所有

我要回帖

更多关于 selenium自动化面试题 的文章

 

随机推荐