底層原理如下:
1.在自動化測試過程中,存在三部分組件:客戶端腳本+驅動+瀏覽器終端。
2.驅動文件,以geckodriver.exe為例,這個可執行的驅動文件啟動后,相當於一個暴露了一系列接口的服務器,監聽某一端口,例如:89890。
3.客戶端的操作(訪問頁面,定位元素,輸入數據,點擊按鈕等)都是封裝成了接口請求(eg:/session/xx/yy),然后提交到驅動服務器。
4.驅動服務器接收到客戶端的請求后,再跟終端瀏覽器交互。
5.終端瀏覽器做出相應操作。
下圖描述了整個交互過程:
以定位元素為例,定位搜索框,我們來看底下這行代碼在執行的時候底層到底經歷了些什么:
WebElement searchInputBox = driver.findElement(By.id("js_keyword"));
實際,底層請求時,每個請求會被封裝為一個command,然后根據不同的commannd封裝得到不同的HttpRequest對象:
根據此命令,得到接口地址:
拿到此接口地址封裝為一個HttpRequest請求。
client.execute(httpRequest,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/:sessionId/log")); defineCommand(GET_AVAILABLE_LOG_TYPES, get("/session/:sessionId/log/types")); defineCommand(SWITCH_TO_FRAME, post("/session/:sessionId/frame")); defineCommand(SWITCH_TO_PARENT_FRAME, post("/session/:sessionId/frame/parent")); defineCommand(CLOSE, delete("/session/:sessionId/window")); defineCommand(SWITCH_TO_WINDOW, post("/session/:sessionId/window")); defineCommand(FULLSCREEN_CURRENT_WINDOW, post("/session/:sessionId/window/fullscreen")); defineCommand(GET_CURRENT_URL, get("/session/:sessionId/url")); defineCommand(GET, post("/session/:sessionId/url")); defineCommand(GO_BACK, post("/session/:sessionId/back")); defineCommand(GO_FORWARD, post("/session/:sessionId/forward")); defineCommand(REFRESH, post("/session/:sessionId/refresh")); defineCommand(SET_ALERT_CREDENTIALS, post("/session/:sessionId/alert/credentials")); defineCommand(UPLOAD_FILE, post("/session/:sessionId/file")); defineCommand(SCREENSHOT, get("/session/:sessionId/screenshot")); defineCommand(ELEMENT_SCREENSHOT, get("/session/:sessionId/screenshot/:id")); defineCommand(GET_TITLE, get("/session/:sessionId/title")); defineCommand(FIND_ELEMENT, post("/session/:sessionId/element")); defineCommand(FIND_ELEMENTS, post("/session/:sessionId/elements")); defineCommand(GET_ELEMENT_PROPERTY, get("/session/:sessionId/element/:id/property/:name")); defineCommand(CLICK_ELEMENT, post("/session/:sessionId/element/:id/click")); defineCommand(CLEAR_ELEMENT, post("/session/:sessionId/element/:id/clear")); defineCommand( GET_ELEMENT_VALUE_OF_CSS_PROPERTY, get("/session/:sessionId/element/:id/css/:propertyName")); defineCommand(FIND_CHILD_ELEMENT, post("/session/:sessionId/element/:id/element")); defineCommand(FIND_CHILD_ELEMENTS, post("/session/:sessionId/element/:id/elements")); defineCommand(IS_ELEMENT_ENABLED, get("/session/:sessionId/element/:id/enabled")); defineCommand(ELEMENT_EQUALS, get("/session/:sessionId/element/:id/equals/:other")); defineCommand(GET_ELEMENT_RECT, get("/session/:sessionId/element/:id/rect")); defineCommand(GET_ELEMENT_LOCATION, get("/session/:sessionId/element/:id/location")); defineCommand(GET_ELEMENT_TAG_NAME, get("/session/:sessionId/element/:id/name")); defineCommand(IS_ELEMENT_SELECTED, get("/session/:sessionId/element/:id/selected")); defineCommand(GET_ELEMENT_SIZE, get("/session/:sessionId/element/:id/size")); defineCommand(GET_ELEMENT_TEXT, get("/session/:sessionId/element/:id/text")); defineCommand(SEND_KEYS_TO_ELEMENT, post("/session/:sessionId/element/:id/value")); defineCommand(GET_ALL_COOKIES, get("/session/:sessionId/cookie")); defineCommand(GET_COOKIE, get("/session/:sessionId/cookie/:name")); defineCommand(ADD_COOKIE, post("/session/:sessionId/cookie")); defineCommand(DELETE_ALL_COOKIES, delete("/session/:sessionId/cookie")); defineCommand(DELETE_COOKIE, delete("/session/:sessionId/cookie/:name")); defineCommand(SET_TIMEOUT, post("/session/:sessionId/timeouts")); defineCommand(SET_SCRIPT_TIMEOUT, post("/session/:sessionId/timeouts/async_script")); defineCommand(IMPLICITLY_WAIT, post("/session/:sessionId/timeouts/implicit_wait")); defineCommand(GET_APP_CACHE_STATUS, get("/session/:sessionId/application_cache/status")); defineCommand(IS_BROWSER_ONLINE, get("/session/:sessionId/browser_connection")); defineCommand(SET_BROWSER_ONLINE, post("/session/:sessionId/browser_connection")); defineCommand(GET_LOCATION, get("/session/:sessionId/location")); defineCommand(SET_LOCATION, post("/session/:sessionId/location")); defineCommand(GET_SCREEN_ORIENTATION, get("/session/:sessionId/orientation")); defineCommand(SET_SCREEN_ORIENTATION, post("/session/:sessionId/orientation")); defineCommand(GET_SCREEN_ROTATION, get("/session/:sessionId/rotation")); defineCommand(SET_SCREEN_ROTATION, post("/session/:sessionId/rotation")); defineCommand(IME_GET_AVAILABLE_ENGINES, get("/session/:sessionId/ime/available_engines")); defineCommand(IME_GET_ACTIVE_ENGINE, get("/session/:sessionId/ime/active_engine")); defineCommand(IME_IS_ACTIVATED, get("/session/:sessionId/ime/activated")); defineCommand(IME_DEACTIVATE, post("/session/:sessionId/ime/deactivate")); defineCommand(IME_ACTIVATE_ENGINE, post("/session/:sessionId/ime/activate")); // Mobile Spec defineCommand(GET_NETWORK_CONNECTION, get("/session/:sessionId/network_connection")); defineCommand(SET_NETWORK_CONNECTION, post("/session/:sessionId/network_connection")); defineCommand(SWITCH_TO_CONTEXT, post("/session/:sessionId/context")); defineCommand(GET_CURRENT_CONTEXT_HANDLE, get("/session/:sessionId/context")); defineCommand(GET_CONTEXT_HANDLES, get("/session/:sessionId/contexts")); }
另外,可能會有人好奇,驅動服務器是何時啟動的服務。其實是在執行下面這行代碼的時候啟動的,大家可執行去debug調試selenium的底層代碼:
//創建火狐驅動對象 WebDriver driver = new FirefoxDriver();
當上面這行代碼執行完,可以發現eclipse的控制台顯示了如下信息:
1531911173760 geckodriver INFO geckodriver 0.19.0 1531911173772 geckodriver INFO Listening on 127.0.0.1:21984
說明此驅動服務器成功啟動了,並且監聽了本機的21984端口,等待客戶端發起請求,並處理。
轉載於:https://www.cnblogs.com/nickjiang/p/9332480.html#4033469