在使用 Selenium WebDriver 作自動化測試的時候,會常常模擬鼠標和鍵盤的一些行爲。好比使用鼠標單擊、雙擊、右擊、拖拽等動做;或者鍵盤輸入、快捷鍵使用、組合鍵使用等模擬鍵盤的操做。在 WebDeriver 中,有一個專門的類來負責實現這些測試場景,那就是 Actions 類,在使用該類的過程當中會配合使用到 Keys 枚舉以及 Mouse、 Keyboard、CompositeAction 等類。html
其次,在實際測試過程當中,可能會遇到某些按鍵沒辦法使用 Actions、Keys 等類來實現的狀況。 好比經過使用 Alt+PrtSc 組合鍵來實現截取屏幕當前活動窗口的圖像,在 Keys 枚舉中,由於沒有枚舉出 PrtSc 鍵,因此沒辦法經過 Action 的 KeyDown(Keys) 來模擬按下這個動做。html5
再次是在自動化測試中,可能會遇到一些附件、文件上傳的場景,或者是多文件上傳,這些在 Selenium2.0 以後,能夠直接使用 WebElement 類的 sendKeys() 方法來實現。java
下面就分別介紹這些狀況的具體使用。數組
鼠標點擊事件有如下幾種類型:瀏覽器
Actions action = new Actions(driver);action.click();// 鼠標左鍵在當前停留的位置作單擊操做 action.click(driver.findElement(By.name(element)))// 鼠標左鍵點擊指定的元素
Actions action = new Actions(driver); action.contextClick();// 鼠標右鍵在當前停留的位置作單擊操做 action.contextClick(driver.findElement(By.name(element)))// 鼠標右鍵點擊指定的元素
Actions action = new Actions(driver); action.doubleClick();// 鼠標在當前停留的位置作雙擊操做 action.doubleClick(driver.findElement(By.name(element)))// 鼠標雙擊指定的元素
Actions action = new Actions(driver); // 鼠標拖拽動做,將 source 元素拖放到 target 元素的位置。 action.dragAndDrop(source,target); // 鼠標拖拽動做,將 source 元素拖放到 (xOffset, yOffset) 位置,其中 xOffset 爲橫座標,yOffset 爲縱座標。 action.dragAndDrop(source,xOffset,yOffset);
在這個拖拽的過程當中,已經使用到了鼠標的組合動做,首先是鼠標點擊並按住 (click-and-hold) source 元素,而後執行鼠標移動動做 (mouse move),移動到 target 元素位置或者是 (xOffset, yOffset) 位置,再執行鼠標的釋放動做 (mouse release)。因此上面的方法也能夠拆分紅如下的幾個執行動做來完成:服務器
action.clickAndHold(source).moveToElement(target).perform(); action.release();
Actions action = new Actions(driver); action.clickAndHold();// 鼠標懸停在當前位置,既點擊而且不釋放 action.clickAndHold(onElement);// 鼠標懸停在 onElement 元素的位置
action.clickAndHold(onElement) 這個方法其實是執行了兩個動做,首先是鼠標移動到元素 onElement,而後再 clickAndHold, 因此這個方法也能夠寫成 action.moveToElement(onElement).clickAndHold()。測試
Actions action = new Actions(driver); action.moveToElement(toElement);// 將鼠標移到 toElement 元素中點 // 將鼠標移到元素 toElement 的 (xOffset, yOffset) 位置, //這裏的 (xOffset, yOffset) 是以元素 toElement 的左上角爲 (0,0) 開始的 (x, y) 座標軸。 action.moveToElement(toElement,xOffset,yOffset) // 以鼠標當前位置或者 (0,0) 爲中心開始移動到 (xOffset, yOffset) 座標軸 action.moveByOffset(xOffset,yOffset);
action.moveByOffset(xOffset,yOffset) 這裏須要注意,若是 xOffset 爲負數,表示橫座標向左移動,yOffset 爲負數表示縱座標向上移動。並且若是這兩個值大於當前屏幕的大小,鼠標只能移到屏幕最邊界的位置同時拋出 MoveTargetOutOfBoundsExecption 的異常。spa
鼠標移動操做在測試環境中比較經常使用到的場景是須要獲取某元素的 flyover/tips,實際應用中不少 flyover 只有當鼠標移動到這個元素以後纔出現,因此這個時候經過執行 moveToElement(toElement) 操做,就能達到預期的效果。可是根據我我的的經驗,這個方法對於某些特定產品的圖標,圖像之類的 flyover/tips 也不起做用,雖然在手動操做的時候移動鼠標到這些圖標上面能夠出現 flyover, 可是當使用 WebDriver 來模擬這一移動操做時,雖然方法成功執行了,可是 flyover 卻出不來。因此在實際應用中,還須要對具體的產品頁面作相應的處理。rest
Actions action = new Actions(driver); action.release();// 釋放鼠標
對於鍵盤的模擬操做,Actions 類中有提供 keyUp(theKey)、keyDown(theKey)、sendKeys(keysToSend) 等方法來實現。鍵盤的操做有普通鍵盤和修飾鍵盤(Modifier Keys, 下面的章節將講到修飾鍵的概念)兩種 :code
1. 對於普通鍵盤,使用 sendKeys(keysToSend) 就能夠實現,好比按鍵 TAB、Backspace 等。
Actions action = new Actions(driver); action.sendKeys(Keys.TAB);// 模擬按下並釋放 TAB 鍵 action.sendKeys(Keys.SPACE);// 模擬按下並釋放空格鍵 /*** 針對某個元素髮出某個鍵盤的按鍵操做,或者是輸入操做, 好比在 input 框中輸入某個字符也可使用這個方法。這個方法也能夠拆分紅: action.click(element).sendKeys(keysToSend)。 */ action.sendKeys(element,keysToSend);
注意除了 Actions 類有 sendKeys(keysToSend)方法外,WebElement 類也有一個 sendKeys(keysToSend)方法,這兩個方法對於通常的輸入操做基本上相同,不一樣點在於如下幾點:
Actions action = New Actions(driver); action.sendKeys(element,「C:\\test\\upload\\test.jpg」); action.click(element).sendKeys(「C:\\test\\upload\\test.jpg」);
這種方式是上傳不成功的,雖然 WebDriver 在執行這條語句的時候不會出錯,可是實際上並無將文件上傳。因此要上傳文件,仍是應該使用前面一種方式。
2.對於修飾鍵(Modifier keys),通常都是跟普通鍵組合使用的。好比 Ctrl+a、Alt+F四、 Shift+Ctrl+F 等等。
Actions action = new Actions(driver); action.keyDown(Keys.CONTROL);// 按下 Ctrl 鍵 action.keyDown(Keys.SHIFT);// 按下 Shift 鍵 action.keyDown(Key.ALT);// 按下 Alt 鍵 action.keyUp(Keys.CONTROL);// 釋放 Ctrl 鍵 action.keyUp(Keys.SHIFT);// 釋放 Shift 鍵 action.keyUp(Keys.ALT);// 釋放 Alt 鍵
因此要經過 Alt+F4 來關閉當前的活動窗口,能夠經過下面語句來實現:action.keyDown(Keys.ALT).keyDown(Keys.F4).keyUp(Keys.ALT).perform();
而若是是對於像鍵盤上面的字母鍵 a,b,c,d... 等的組合使用,能夠經過如下語句實現 :action.keyDown(Keys.CONTROL).sednKeys(「a」).perform();
在 WebDriver API 中,KeyDown(Keys theKey)、KeyUp(Keys theKey) 方法的參數只能是修飾鍵:Keys.SHIFT、Keys.ALT、Keys.CONTROL, 否者將拋出 IllegalArgumentException 異常。 其次對於 action.keyDown(theKey) 方法的調用,若是沒有顯示的調用 action.keyUp(theKey) 或者 action.sendKeys(Keys.NULL) 來釋放的話,這個按鍵將一直保持按住狀態。
1.在 WebDriver 中,Keys 枚舉出了鍵盤上大多數的非字母類按鍵,從 F1 到 F10,NUMPAD0 到 NUMPAD九、ALT\TAB\CTRL\SHIFT 等等,你能夠經過如下連接查看 Keys 枚舉出來的全部按鍵,Enum Keys。 可是並無列出鍵盤上的全部按鍵,好比字母鍵 a、b、c、d … z,一些符號鍵好比:‘ {}\[] ’、‘ \ ’、‘。’、‘ ? ’、‘:’、‘ + ’、‘ - ’、‘ = ’、、‘「」’,還有一些不經常使用到的功能鍵如 PrtSc、ScrLk/NmLk。對於字母鍵和符號鍵,前面咱們已經提到能夠直接使用 sendKeys(「a」),sendKeys(「/」) 的方式來觸發這些鍵盤事件。而對於一些功能組合鍵,如 Fn + NmLk 來關閉或者打開數字鍵,或者 Alt+PrtSC 來抓取當前屏幕的活動窗口並保存到圖片,經過 WebDriver 的 Keys 是沒辦法操做的。 這個時候咱們就須要用到 Java 的 Robot 類來實現對這類組合鍵的操做了。
2.下面就以對 Alt+PrtSc 爲例介紹一下 Robot 對鍵盤的操做。如代碼清單 10。
/** * * @Description: 這個方法用來模擬發送組合鍵 Alt + PrtSc, 當組合鍵盤事件執行以後,屏幕上的活動窗口 * 就被截取而且存儲在剪切板了。 接下來就是經過讀取剪切板數據轉換成 Image 圖像對象並保存到本地。 * @param filename : 要保存的圖像的名稱 */ public static void sendComposeKeys(String fileName) throws Exception { // 構建 Robot 對象,用來操做鍵盤 Robot robot = new Robot(); // 模擬按下鍵盤動做,這裏經過使用 KeyEvent 類來獲取對應鍵盤(ALT)的虛擬鍵碼 robot.keyPress(java.awt.event.KeyEvent.VK_ALT); // 按下 PrtSC 鍵 robot.keyPress(java.awt.event.KeyEvent.VK_PRINTSCREEN); // 釋放鍵盤動做,當這個動做完成以後,模擬組合鍵 Alt + PrtSC 的過程就已經完成, //此時屏幕活動窗口就一被截取並存入到剪切板 robot.keyRelease(java.awt.event.KeyEvent.VK_ALT); // 獲取系統剪切板實例 Clipboard sysc = Toolkit.getDefaultToolkit().getSystemClipboard(); // 經過 getContents() 方法就能夠將剪切板內容獲取並存入 Transferable 對象中 Transferable data = sysc.getContents(null); if (data != null) { /*** 判斷從剪切板獲取的對象內容是否爲 Java Image 類, 若是是將直接轉化爲 Image 對象。 到此爲止,咱們就從發出組合鍵到抓取活動窗口,再讀取剪切板並存入 Image 對象的過程 就完成了,接下來要作的就是須要將 Image 對象保存到本地。 */ if (data.isDataFlavorSupported(DataFlavor.imageFlavor)) { Image image = (Image) data .getTransferData(DataFlavor.imageFlavor); writeImageToFile(image, fileName); } } }
Robot 類對鍵盤的處理是經過 keyPress(int keycode)、keyRelease(int keycode) 方法來實現的,其中他們須要的參數是鍵盤按鍵對應的虛擬鍵碼,虛擬鍵碼的值能夠經過 KeyEvent 類來獲取。在 Java API 中對於虛擬鍵碼的解釋以下: 虛擬鍵碼用於報告按下了鍵盤上的哪一個鍵,而不是一次或屢次鍵擊組合生成的字符(如 "A" 是由 shift + "a" 生成的)。 例如,按下 Shift 鍵會生成 keyCode 爲 VK_SHIFT 的 KEY_PRESSED 事件,而按下 'a' 鍵將生成 keyCode 爲 VK_A 的 KEY_PRESSED 事件。釋放 'a' 鍵後,會激發 keyCode 爲 VK_A 的 KEY_RELEASED 事件。另外,還會生成一個 keyChar 值爲 'A' 的 KEY_TYPED 事件。 按下和釋放鍵盤上的鍵會致使(依次)生成如下鍵事件:
KEY_PRESSED
KEY_TYPED(只在可生成有效 Unicode 字符時產生。)
KEY_RELEASED
因此當測試中須要用到按下鍵盤 Alt+PrtSc 鍵的時候,只須要執行代碼清單 10 中兩個 keyPress() 和一個 keyRelease() 方法便可。
3.當這兩個按鍵執行結束以後,屏幕上面的活動窗口已經保存到剪切板中。若是須要將其保存本地圖片,只須要從剪切板讀取並經過 JPEGImageEncoder 類或者 ImageIO 類將其寫入本地便可。
/** * * @Description: 這個方法用來將 Image 對象保存到本地,主要是經過 JPEGImageEncoder 類來實現圖像的 * 保存 * @param image : 要保存的 Image 對象 * @param filename : 保存圖片的文件名稱 */ public static void writeImageToFile(Image image, String fileName) { try { // 獲取 Image 對象的寬度和高度, 這裏的參數爲 null 表示不須要通知任何觀察者 int width = image.getWidth(null); int height = image.getHeight(null); BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); // 經過 BufferedImage 繪製圖像並保存在其對象中 bi.getGraphics().drawImage(image, 0, 0, null); // 構建圖像名稱及保存路徑 String name = Const.DIRECTORY + fileName + Const.FORMAT; File dir = new File(Const.DIRECTORY); if (!dir.exists()) { dir.mkdir(); } FileOutputStream out = new FileOutputStream(name); @SuppressWarnings("restriction") JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out); encoder.encode(bi); out.flush(); out.close(); } catch (Exception e) { e.printStackTrace(); } }
代碼清單 11 是經過 JPEGImageEncoder 類將 Image 對象寫到本地文件流,注意 Image 對象是在代碼清單 10 中的以下語句獲取到的:
Clipboard sysc = Toolkit.getDefaultToolkit().getSystemClipboard(); Transferable data = sysc.getContents(null); if (data != null) { if (data.isDataFlavorSupported(DataFlavor.imageFlavor)) { Image image = (Image) data .getTransferData(DataFlavor.imageFlavor); writeImageToFile(image, fileName); } }
/** * * @Description: 經過使用 ImageIO 類來保存 Image 對象爲本地圖片 * @param image : 須要保存的 Image 對象 * @param filename : 文件名 */ public static void saveImage(Image image, String fileName) throws Exception { // 獲取 Image 對象的高度和寬度 int width = image.getWidth(null); int height = image.getHeight(null); BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); Graphics g = bi.getGraphics(); //經過 BufferedImage 繪製圖像並保存在其對象中 g.drawImage(image, 0, 0, width, height, null); g.dispose(); File f = new File(fileName); // 經過 ImageIO 將圖像寫入到文件 ImageIO.write(bi, "jpg", f); }
在 Selenium2.0 以前,要上傳文件是比較麻煩的一件事件,由於點擊 Upload File 控件會彈出 Windows 窗口以提供用戶選擇文件,可是 Window 窗口已是瀏覽器以外的組件,因此 Selenium 自己沒辦法控制, 而必須使用 Java Robot 類來模擬鍵盤去操做剪切板實現上傳功能,並且及其不穩定。 在 Selenium 2.0 以後,WebDriver 解決了這個問題。前面已經談到過,直接使用 WebElement 類的 sendKeys(keysToSend) 方法就能夠實現文件上傳了。可是若是想批量上傳文件,使用 element.sendKeys(「C:\\test\\upload\\test1.txt」, 「C:\\test\\upload\\test2.txt」...) 方法也是不行的,它能經過執行,可是實際上沒有上傳成功。這時能夠經過循環的方式來實現文件的批量上傳,代碼清單 13 是我在百度雲上面批量上傳文件的測試。
/** * * @Description: 在百度雲上測試文件批量上傳功能,主要是經過循環的方式去作單一 * 的上傳動做 , 登錄過程已經去掉 */ @Test public void test_mutilUploadFile() throws Exception { System.out.println("upload start"); // 獲取上傳控件元素 WebElement uploadButton = driver.findElement(By.name("html5uploader")); // 構建上傳文件路徑,將須要上傳的文件添加到 CharSequence 數組 CharSequence[] files = new CharSequence[5]; files[0] = "C:\\test\\test1.txt"; files[1] = "C:\\test\\test2.txt"; files[2] = "C:\\test\\test3.txt"; files[3] = "C:\\test\\test4.txt"; files[4] = "C:\\test\\test5.txt"; // 循環列出每支須要上傳的文件路徑,作單一上傳動做 for(CharSequence file: files){ uploadButton.sendKeys(file); } Thread.sleep(2000); System.out.println("upload end"); }
在 Selenium WebDriver 中,有了 Actions 類和 Keys 枚舉對鍵盤和鼠標的操做已經作的很是到位,再結合 Java 自己 Robot、KeyEvent 等類的使用,基本上能夠知足工做中遇到的對鼠標鍵盤操做的應用了。
其次要注意的地方是 WebDriver 對瀏覽器的支持問題,Selenium WebDriver 支持的瀏覽器很是普遍,從 IE、Firefox、Chrome 到 Safari 等瀏覽器, WebDriver 都有相對應的實現:InterntExplorerDriver、FirefoxDriver、ChromeDriver、SafariDriver、AndroidDriver、 IPhoneDriver、HtmlUnitDriver 等。根據我的的經驗,Firefox 以及 Chrome 瀏覽器對 WebDriver 的支持最好了,Firefox 搭上 Firebug 以及 Firepath, 在寫腳本的過程當中很是方便,而 ChromeDriver 是 Google 公司本身支持與維護的項目。HtmlUnitDriver 速度最快,一個純 Java 實現的瀏覽器。IE 比較慢,並且對於 Xpath 等支持不是很好。