Selenium自动化测试框架研究
1. 介绍
Selenium这个单词的字面意思是"硒",Selenium的官方网站是
2. 编译Seleniumgit clone http://selenium.googlecode.com/git/ selenium
在terminal下进入selenium目录,输入,./go
或者,./go clean release
等待编译完成。
我在编译过程出现依赖性错误,需要libibus-dev包。
3. Selenium IDE
Selenium IDE是一个Firefox下的插件,可以使用Firefox直接从selenium的网站上安装。
Selenium IDE是一个简单的Selenium的脚本录制、编辑和验证工具,可以用于测试用例的录制,并且可以把selenium的测试脚本转换成其它的语言,如:java、python等。
4. Selenium Remote Control
Selenium Remote Control是测试服务,可以使用selenium client把测试任务指派给selenium rc,让其执行。
通常情况下都是使用selenium rc + selenium client + selenium ide的模式来完成测试任务。
5. Selenium的编译环境
5.1. 概述
Selenium编译是从目录下的go(for linux)/go.bat(for windows)这两个文件开始的。go文件的内容如下:
# we want jruby-complete to take care of all things ruby
unsetGEM_HOME
unsetGEM_PATH
JAVA_OPTS="-client"
java$JAVA_OPTS-Xmx2048m -XX:MaxPermSize=1024m -XX:ReservedCodeCacheSize=256m -jar third_party/jruby/jruby-complete.jar -X-C -S rake$*
go.bat的大致相同。
Rakefile是Rake构建工程使用的工程文件,相当于Makefile,Rakefile的语法是基于ruby的。
5.2. Rakefile
5.2.1. 介绍
Selenium使用Rake作为构建环境,rake是一个基于ruby语言的与makefile相似的跨平台的多任务的构建系统,其官方网站是
Rake构建系统的构建文件是Rakefile,到selenium项目的根目录下,可以找到selenium的Rakefile文件。Rakefile的语法基础是ruby,可以从rake的官方网站上找到具体的语法说明及例程。
5.2.2. Selenium的Rakefile
5.2.2.1. 导入crazyfun依赖
Toggle line numbers# The CrazyFun build grammar. There's no magic here, just ruby
require'rake-tasks/crazy_fun'
require'rake-tasks/crazy_fun/mappings/android'
require'rake-tasks/crazy_fun/mappings/export'
require'rake-tasks/crazy_fun/mappings/folder'
require'rake-tasks/crazy_fun/mappings/gcc'
require'rake-tasks/crazy_fun/mappings/java'
require'rake-tasks/crazy_fun/mappings/javascript'
require'rake-tasks/crazy_fun/mappings/mozilla'
require'rake-tasks/crazy_fun/mappings/python'
require'rake-tasks/crazy_fun/mappings/rake'
require'rake-tasks/crazy_fun/mappings/rename'
require'rake-tasks/crazy_fun/mappings/ruby'
require'rake-tasks/crazy_fun/mappings/visualstudio'
5.2.2.2. 导入其它的依赖
Toggle line numbers# The original build rules
require'rake-tasks/task-gen'
require'rake-tasks/checks'
require'rake-tasks/dotnet'
require'rake-tasks/zip'
require'rake-tasks/c'
require'rake-tasks/java'
require'rake-tasks/iphone'
require'rake-tasks/selenium'
require'rake-tasks/se-ide'
require'rake-tasks/ie_code_generator'
require'rake-tasks/ci'
require'rake-tasks/gecko_sdks'
5.2.2.3. 使用crazyfun
Toggle line numbers# The build system used by webdriver is layered on top of rake, and we call it
# "crazy fun" for no readily apparent reason.
# First off, create a new CrazyFun object.
crazy_fun=CrazyFun.new
# Secondly, we add the handlers, which are responsible for turning a build
# rule into a (series of) rake tasks. For example if we're looking at a file
# in subdirectory "subdir" contains the line:
# java_library(:name => "example", :srcs => ["foo.java"])
# we would generate a rake target of "//subdir:example" which would generate
# a Java JAR at "build/subdir/example.jar".
# If crazy fun doesn't know how to handle a particular output type ("java_library"
# in the example above) then it will throw an exception, stopping the build
AndroidMappings.new.add_all(crazy_fun)
ExportMappings.new.add_all(crazy_fun)
FolderMappings.new.add_all(crazy_fun)
GccMappings.new.add_all(crazy_fun)
JavaMappings.new.add_all(crazy_fun)
JavascriptMappings.new.add_all(crazy_fun)
MozillaMappings.new.add_all(crazy_fun)
PythonMappings.new.add_all(crazy_fun)
RakeMappings.new.add_all(crazy_fun)
RenameMappings.new.add_all(crazy_fun)
RubyMappings.new.add_all(crazy_fun)
VisualStudioMappings.new.add_all(crazy_fun)
这里可以看到rakefile通过crazyfun实现了对各种编译环境的支持,如:Android、Java、Gcc及VS等。
5.2.2.4. 创建crazyfun的任务
Toggle line numbers# Finally, find every file named "build.desc" in the project, and generate
# rake tasks from them. These tasks are normal rake tasks, and can be invoked
# from rake.
crazy_fun.create_tasks(Dir["**/build.desc"])
这里在工程的所有子目录中查找build.desc文件,并根据build.desc创建rake中的任务。
5.3. CrazyFunBuild
5.3.1. 介绍
如果需要修改或是扩展Selenium中的包或库,就要修改对应的包或库的build.desc文件,把增加的源代码和路径显式的或隐式的添加到对应的包/库中。
5.3.2. CrazyFun的简单说明
其实在rakefile的crazyfun那一段中也有一个简单的Java的例子,如下:
java_library(name="example",
resources=["example.java"],
deps=[":base"])
上面这个build.desc的说明:用Java编译,生成一个名为example.jar的包;
编译的源文件是当前目录下的example.java
example项目编译依赖于base.jar
5.3.3. 在Selenium进行Java二次开发
5.3.3.1. 创建Java工程
根据Selenium的目录结构来看,可以使用Eclipse或其它的IDE创建Java工程,工程创建完成后,如果需要在Rakefile中统一编译,则需要在对应的源代码目录中增加build.desc。
下面代码是{$SeleniumHome}/java/server/src/org/openqa/selenium/server目录下的build.desc文件,
java_binary(name="server",
main_class="org.openqa.selenium.server.SeleniumServer",
deps= [
":base",
":server_resources",
"//java/client/src/org/openqa/selenium:client-combined",
"//third_party/java/opera-driver",
])
# Light version of the server for drivers that don't need to depend on all other drivers.
# We need at least one source file in here to make this build the JAR
# TODO(simon): Only resources should be fine
java_binary(name="server_lite",
main_class="org.openqa.selenium.server.SeleniumServer",
deps= [
":base",
":server_resources",
])
java_library(name="server_resources",
resources= [
"customProfileDirCUSTFF",
"customProfileDirCUSTFFCHROME",
"hudsuckr",
"konqueror",
"opera",
"sslSupport",
"VERSION.txt",
],
deps= [
"//javascript/selenium-core"
])
java_library(name="logging",
srcs= [
"RemoteControlConfiguration.java",
"SslCertificateGenerator.java",
],
deps= [
"//java/client/src/org/openqa/selenium/remote:common",
"//java/server/src/org/openqa/jetty",
"//java/client/src/org/openqa/selenium/logging:api",
"//java/client/src/org/openqa/selenium/logging:logging",
"//java/server/src/org/openqa/selenium/remote/server/log",
])
java_library(name="base",
srcs= [
"**/*.java",
],
deps= [
":logging",
"//java/client/src/org/openqa/selenium:codecs",
"//java/client/src/org/openqa/selenium:selenium-api",
"//java/client/src/org/openqa/selenium/browserlaunchers:launcher-utils",
"//java/client/src/org/openqa/selenium/net",
"//java/client/src/org/openqa/selenium/support",
"//java/server/src/cybervillains",
"//java/server/src/org/openqa/selenium/remote/server",
"//java/server/src/org/openqa/jetty",
"//third_party/java/servlet-api"
])
从上面代码可以看出,在srcs中既可以使用完整的路径,也可以使用通配符*.java。
下面单独以"server"这个task为例进行说明:
java_binary(name="server",
main_class="org.openqa.selenium.server.SeleniumServer",
deps=[
":base",
":server_resources",
"//java/client/src/org/openqa/selenium:client_combined",
"//third_party/java/opera-driver"
])
说明:java_binary说明这个task是生成一个可以执行的jar包,在生成的MANIFEST.MF文件里有Main-Class;
name是指出生成的jar包的名字;
main_class指出这个可执行的jar包的入口点是MANIFEST.MF文件,如:"Main-Class:org.openqa.selenium.server.SeleniumServer";
":base"是本地的依赖关系,"//third_party/java/opera-driver"这样的写法是指出非本地的依赖包。
5.3.4. 在Selenium中进行C or C++ 二次开发
Selenium中的C/C++模块由cpp目录下的build.desc在管理,按照Selenium的目录结构,由C或C++开发的库或应用程序工程都放在cpp目录,并且在build.desc中添加对应的task。
下面具体分析build.desc的内容。
5.3.4.1. GCC编译
Toggle line numbersgcc_library(name="noblur",
srcs= ["linux-specific/*.c"],
args="-I/usr/include",
arch="i386")
gcc_library(name="noblur64",
srcs= ["linux-specific/*.c"],
args="-I/usr/include",
arch="amd64")
说明:"gcc_library"指出输出一个.a或.so的库文件;
"srcs"需要编译的.c文件的路径;
"args"是一些需要的编译参数,如:"-I"、"-L"等;
"arch"是编译器的架构,i386是32位,amd64是64位。
5.3.4.2. VS编译
Toggle line numbersvisualc_library(name="firefox_dll",
platform="Win32",
project="webdriver-firefox/webdriver-firefox.vcxproj",
file_deps="third_party/gecko-2/win32",
out="Win32/Release/webdriver-firefox.dll"
)
visualc_release(name="ie_win32_exe",
deps= [
":atoms",
":ie_result_type_cpp",
":sizzle"
],
platform="Win32",
project="IEDriverServer/IEDriverServer.vcxproj",
desc="InternetExplorerDriver standalone server for 32-bit IE",
out="Win32/Release/IEDriverServer.exe"
说明:"visualc_library"是输出一个windows操作系统下的DLL库文件;
"visualc_release"是输出一个windows操作系统下的可执行文件;
"platform"如果是"win32",则输出32位版本,如果是"x64",则输出64位的版本;
"project"是指vs的工程文件的路径;
"deps"是库依赖;
6. Selenium工程的调试(for linux)
6.1. 调试环境的准备
从Selenium的工程目录来看,Selenium中的Java部件可以使用Eclipse或Intellij IDEA打开。
如果需要调试C/C++的代码需要在windows操作系统下装有Visual Studio 10以上版本或linux操作系统下gcc + gdb支持。
6.2. Java代码的调试
6.2.1. Eclipse导入Selenium
在eclipse的menu下的"file">>"import"打开import对话框,
选择"Existing Projects into Workspace",
选择selenium工程的顶级目录,
在"Projects"中选择要导入的工程,除了"android"以外的工程,"client"、"server"、"selenium-common"、"third-party"全部都要导入。
6.2.2. 用debug模式启动Selenium Server
打开"selenium/java/server/src/org/openqa/selenium/server"目录下的"build.desc"文件,找到如下,
java_binary(name="server",
main_class="org.openqa.selenium.server.SeleniumServer",
deps= [
":base",
":server_resources",
"//java/client/src/org/openqa/selenium:client-combined",
"//third_party/java/opera-driver",
])
根据main_class中所指出的,打开"Debug As">>"Java Application",如果没有错误,服务器就会正常启动并监听0.0.0.0:4444地址。
6.2.3. 访问测试服务器
使用selenium简单录制一个testcase,把这个case转为python代码,如下,
fromseleniumimportselenium
importunittest,time,re
classtestng(unittest.TestCase):
defsetUp(self):
self.verificationErrors= []
self.selenium=selenium("localhost",4444,"*chrome","http://www.baidu.com/")
self.selenium.start()
deftest_testng(self):
sel=self.selenium
sel.open("/")
sel.type("id=kw","testng")
sel.click("id=su")
sel.wait_for_page_to_load("30000")
deftearDown(self):
self.selenium.stop()
self.assertEqual([],self.verificationErrors)
if__name__=="__main__":
unittest.main()
上述内容保存为test.py文件放到,selenium工程的py目录下,一种方式是在console里输入,python test.py
另一种方式是用sublimetext打开test.py,快捷键Ctrl+B运行。
运行测试代码后,可以在eclipse下的console窗口看到server运行输出的log及其它信息。
6.3. C/C++代码的调试
分析gcc.rb文件后可知,linux版本没有启用调试选项,最终输出的代码使用了"-Os"优化选项,因此最终输出的so文件中不包含符号链接,可以通过两种方式解决C/C++代码的调试,-是在gcc.rb中启用"-g -DDBUG=1",打开调试,生成debug版本的so文件;另一个方法是在windows下用VS进行调试。
在Eclipse中搜索关键字"native",可以发现C++的工程生成的DLL或是SO文件都在client中调用,与Server无关。
6.3.1. 在Visual Studio 12中打开selenium的webdriver工程
在selenium的最上层目录下,找到webdriver.sln文件,双击,让visual studio打开这个文件(假设已经安装了Visual Studio 10以上版本),
如果打开没有发生错误,就可以看到如下,
过滤一下,如下图所示,