web自动化原理揭秘

做过两年自动化测试的小伙伴说web自动化测试真的不难,无非就是一些浏览器操作,页面元素操作,常规的情况很容易处理,再学一学特殊元素的处理,基本就能应付项目的测试了。正是因为软件测试的迅猛发展,所以给行业也带来了新的契机。
这个话倒没错,但是真正要学好自动化测试,深入自动化,并不是那么简单。首先你得懂原理吧,原理不懂,你就不知道怎么解决一些异常情况,也无法完成拓展。其次你得学会写自己的测试框架吧,一个项目写了100个测试类,都是零散的脚本,没有任何设计而言,都是纯粹的业务代码,那我可以说,换了项目你这些脚本就成了垃圾,因此,我们要做自动化,要成为自动化大牛,就一定要花时间去要搞清楚自动化实现的原理,并且学会自己去实现自动化测试框架,乃至于自动化测试平台。
下面一段代码实现了一个很简单的功能:
1打开浏览器
2访问页面“:keqqcom”
3定位到页面的搜索框
4输入查询数据
5定位搜索按钮
6点击搜索按钮,完成搜索
代码如下图:  package webdemo;
import orgopenqaseleniumby;
import orgopenqaseleniumwebdriver;
import orgopenqaseleniumwebelement;
import orgopenqaseleniumfirefoxfirefoxdriver;
import orgtestngannotationstest;
public class demo1 {
@test
public void test(){
设置可执行的驱动文件路径
systemsetproperty("webdrivergeckodriver", "srctestresourcesgeckodriverexe");
创建火狐驱动对象
webdriver driver = new firefoxdriver();
访问课堂首页
driverget("keqqcom");
定位页面的搜索框
webelement searchinputbox = driverfindelement(byid("js_keyword"));
往搜索框输入数据
searchinputboxsendkeys("柠檬班");
定位到搜索按钮
webelement searchbutton = driverfindelement(byid("js_search"));
点击搜索
searchbuttonclick();
}
}
驱动文件位置:
需求很简单,代码也很简单。但是你知道代码中的这些浏览器操作,元素操作,是如何完成的吗?
比如,浏览器启动完成后,再调用:driverget("keqqcom");就能在导航栏中访问到指定的这个页面,这个里面发生了什么,到底是客户端脚本直接操作浏览器还是通过某些中间件来完成??
底层原理如下:
1在自动化测试过程中,存在三部分组件:客户端脚本+驱动+浏览器终端。
2驱动文件,以geckodriverexe为例,这个可执行的驱动文件启动后,相当于一个暴露了一系列接口的服务器,监听某一端口,例如:89890。
3客户端的操作(访问页面,定位元素,输入数据,点击按钮等)都是封装成了接口请求(eg:sessionxxyy),然后提交到驱动服务器。
4驱动服务器接收到客户端的请求后,再跟终端浏览器交互。
5终端浏览器做出相应操作。
下图描述了整个交互过程:
以定位元素为例,定位搜索框,我们来看底下这行代码在执行的时候底层到底经历了些什么:webelement searchinputbox = driverfindelement(byid("js_keyword"));
实际,底层请求时,每个请求会被封装为一个command,然后根据不同的commannd封装得到不同的httprequest对象:
根据此命令,得到接口地址:
拿到此接口地址封装为一个httprequest请求。
clientexecute(request,true),执行接口调用:
至于其他操作:往输入框输入数据,点击按钮等,都是对应一个接口地址,通过调用接口,请求驱动来处理,最后驱动同浏览器进行交互,浏览器按照指示做出对应操作。
selenium有一个类abstracthttpcommandcodec,此类中维护了众多自动化操作对应的接口地址: public abstracthttpcommandcodec() {
definecommand(status, get("status"));
definecommand(get_all_sessions, get("sessions"));
definecommand(new_session, post("session"));
definecommand(get_capabilities, get("session:sessionid"));
definecommand(quit, delete("session:sessionid"));
definecommand(get_session_logs, post("logs"));
definecommand(get_log, post("session:sessionidlog"));
definecommand(get_available_log_types, get("session:sessionidlogtypes"));
definecommand(switch_to_frame, post("session:sessionidframe"));
definecommand(switch_to_parent_frame, post("session:sessionidframeparent"));
definecommand(close, delete("session:sessionidwindow"));
definecommand(switch_to_window, post("session:sessionidwindow"));
definecommand(fullscreen_current_window, post("session:sessionidwindowfullscreen"));
definecommand(get_current_url, get("session:sessionidurl"));
definecommand(get, post("session:sessionidurl"));
definecommand(go_back, post("session:sessionidback"));
definecommand(go_forward, post("session:sessionidforward"));
definecommand(refresh, post("session:sessionidrefresh"));
definecommand(set_alert_credentials, post("session:sessionidalertcredentials"));
definecommand(upload_file, post("session:sessionidfile"));
definecommand(screenshot, get("session:sessionidscreenshot"));
definecommand(element_screenshot, get("session:sessionidscreenshot:id"));
definecommand(get_title, get("session:sessionidtitle"));
definecommand(find_element, post("session:sessionidelement"));
definecommand(find_elements, post("session:sessionidelements"));
definecommand(get_element_property, get("session:sessionidelement:idproperty:name"));
definecommand(click_element, post("session:sessionidelement:idclick"));
definecommand(clear_element, post("session:sessionidelement:idclear"));
definecommand(
get_element_value_of_css_property,
get("session:sessionidelement:idcss:propertyname"));
definecommand(find_child_element, post("session:sessionidelement:idelement"));
definecommand(find_child_elements, post("session:sessionidelement:idelements"));
definecommand(is_element_enabled, get("session:sessionidelement:idenabled"));
definecommand(element_equals, get("session:sessionidelement:idequalsther"));
definecommand(get_element_rect, get("session:sessionidelement:idrect"));
definecommand(get_element_location, get("session:sessionidelement:idlocation"));
definecommand(get_element_tag_name, get("session:sessionidelement:idname"));
definecommand(is_element_selected, get("session:sessionidelement:idselected"));
definecommand(get_element_size, get("session:sessionidelement:idsize"));
definecommand(get_element_text, get("session:sessionidelement:idtext"));
definecommand(send_keys_to_element, post("session:sessionidelement:idvalue"));
definecommand(get_all_cookies, get("session:sessionidcookie"));
definecommand(get_cookie, get("session:sessionidcookie:name"));
definecommand(add_cookie, post("session:sessionidcookie"));
definecommand(delete_all_cookies, delete("session:sessionidcookie"));
definecommand(delete_cookie, delete("session:sessionidcookie:name"));
definecommand(set_timeout, post("session:sessionidtimeouts"));
definecommand(set_script_timeout, post("session:sessionidtimeoutsasync_script"));
definecommand(implicitly_wait, post("session:sessionidtimeoutsimplicit_wait"));
definecommand(get_app_cache_status, get("session:sessionidapplication_cachestatus"));
definecommand(is_browser_online, get("session:sessionidbrowser_connection"));
definecommand(set_browser_online, post("session:sessionidbrowser_connection"));
definecommand(get_location, get("session:sessionidlocation"));
definecommand(set_location, post("session:sessionidlocation"));
definecommand(get_screen_orientation, get("session:sessionidorientation"));
definecommand(set_screen_orientation, post("session:sessionidorientation"));
definecommand(get_screen_rotation, get("session:sessionidrotation"));
definecommand(set_screen_rotation, post("session:sessionidrotation"));
definecommand(ime_get_available_engines, get("session:sessionidimeavailable_engines"));
definecommand(ime_get_active_engine, get("session:sessionidimeactive_engine"));
definecommand(ime_is_activated, get("session:sessionidimeactivated"));
definecommand(ime_deactivate, post("session:sessionidimedeactivate"));
definecommand(ime_activate_engine, post("session:sessionidimeactivate"));
mobile spec
definecommand(get_network_connection, get("session:sessionidnetwork_connection"));
definecommand(set_network_connection, post("session:sessionidnetwork_connection"));
definecommand(switch_to_context, post("session:sessionidcontext"));
definecommand(get_current_context_handle, get("session:sessionidcontext"));
definecommand(get_context_handles, get("session:sessionidcontexts"));
}
另外,可能会有人好奇,驱动服务器是何时启动的服务。其实是在执行下面这行代码的时候启动的,大家可执行去debug调试selenium的底层代码: 创建火狐驱动对象
webdriver driver = new firefoxdriver();
当上面这行代码执行完,可以发现eclipse的控制台显示了如下信息: 1531911173760geckodriverinfogeckodriver 0190
1531911173772geckodriverinfolistening on 127001:21984
说明此驱动服务器成功启动了,并且监听了本机的21984端口,等待客户端发起请求,并处理。