自動化測試selenium在小公司的成功實踐
本文可能是目前最完整的一篇selenium(java版)實踐文章,不是之一。
如果你是java開發人員,本文將幫助你快速搭建整套selenium自動化測試框架,你可以幫助公司升級為自動化測試架構;
如果你是測試人員,那你得按照本文多實踐一下,遇到不懂的諮詢下公司的java開發,同樣你也可以完成自動化測試架構升級。
當然啦,如果目前公司已經是自動化測試了,那本文就當是再次梳理下相關知識吧。
前言
可能提到自動化測試selenium,大家都會想到用python語言來編寫指令碼。但我們選擇了java語言,因為我相信大部分公司java程式設計師比python程式設計師多得多。而對於很多測試人員,並不能熟練使用程式語言,所以他們需要別人指導。與其使用更簡單的python語言,卻看不懂語法,得不到別人幫助;那還不如使用java語言,無論是語法還是程式設計思路,都可以快速獲得java開發人員的幫助。
背景
可能很多公司已經有標準的後端單元測試程式碼,但是自動化測試需要測試整個系統,前端是直接展示給使用者的,所以,前端尤為重要,本文就是基於h5的web前端自動化測試。當然啦,這裡推薦對專案進行前後端分離,如果專案沒有前後端分離可參考某小公司RESTful、共用介面、前後端分離、介面約定的實踐。
目前網際網路上關於selenium完整的文章很少,也很難買到一個專門講selenium的書籍,這讓很多測試人員無從下手,而本文會彌補這一問題,儘可能詳細完整介紹selenium的實踐,提供一個簡易版的完整專案程式碼在github上(因為公司專案程式碼沒有脫敏,不能直接放到github上)。
相關知識
- html標籤
- css樣式
- js基礎
- java基礎
- bat指令碼基礎
首先html由標籤<x></x>
組成,詳細本文會在真實專案中一一介紹。
正式實踐
安裝火狐瀏覽器
因為selenium在火狐瀏覽器裡,可以自動化錄製指令碼,我們通過指令碼錄製可以生成出不同的語言指令碼,可以省去我們90%的編寫指令碼工作量。
可以安裝最新版的火狐瀏覽器,然後安裝Katalon Recorder (Selenium IDE for Firefox)
使用火狐瀏覽器開啟https://addons.mozilla.org/zh-CN/firefox/addon/katalon-automation-record/?src=search
錄製指令碼
以百度搜索掘金為例
1. 位址列開啟百度
2. 右上角,開啟Katalon擴充套件
3. 點選Katalon的New
4. 點選 Record
5. 網頁中輸入 掘金網
6. 開啟第一個掘金官網
7. 在掘金官網搜尋我以前寫的一篇文章 我是如何重構整個研發專案,促進自動化運維DevOps的落地?
8. 點選第一條 我是如何重構整個研發專案,促進自動化運維DevOps的落地?
9. 點選Katalon的stop
每執行一個操作右下角都會提示
錄製後的效果圖
執行、分析指令碼
錄製後,我們點選一下play,可以看到火狐瀏覽器自動化的完成了我們剛剛的操作(關閉彈窗阻止,或者將掘金和百度加入不阻止彈窗列表)
點選Export
可以看到有各種語言 C#、Java、katalon、python2等。
我們先看看python2的指令碼
# -*- coding: utf-8 -*-
from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.support.ui import Select
from selenium.common.exceptions import NoSuchElementException
from selenium.common.exceptions import NoAlertPresentException
import unittest, time, re
class Test(unittest.TestCase):
def setUp(self):
self.driver = webdriver.Firefox()
self.driver.implicitly_wait(30)
self.base_url = "https://www.katalon.com/"
self.verificationErrors = []
self.accept_next_alert = True
def test_(self):
driver = self.driver
driver.get("https://www.baidu.com/index.php?tn=monline_3_dg")
driver.find_element_by_id("kw").click()
driver.find_element_by_id("kw").clear()
driver.find_element_by_id("kw").send_keys(u"掘金網")
driver.find_element_by_xpath("//div[@id='container']/div[2]/div").click()
driver.find_element_by_link_text(u"掘金- juejin.im - 一個幫助開發者成長的社群").click()
# ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
driver.find_element_by_xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").click()
driver.find_element_by_xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").click()
driver.find_element_by_xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").clear()
driver.find_element_by_xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").send_keys(u"我是如何重構整個研發專案,促進自動化運維DevOps的落地?")
driver.find_element_by_xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input").send_keys(Keys.ENTER)
driver.find_element_by_link_text(u"我是如何重構整個研發專案,促進自動化運維DevOps的落地?").click()
def is_element_present(self, how, what):
try: self.driver.find_element(by=how, value=what)
except NoSuchElementException as e: return False
return True
def is_alert_present(self):
try: self.driver.switch_to_alert()
except NoAlertPresentException as e: return False
return True
def close_alert_and_get_its_text(self):
try:
alert = self.driver.switch_to_alert()
alert_text = alert.text
if self.accept_next_alert:
alert.accept()
else:
alert.dismiss()
return alert_text
finally: self.accept_next_alert = True
def tearDown(self):
self.driver.quit()
self.assertEqual([], self.verificationErrors)
if __name__ == "__main__":
unittest.main()
我們再看看java junit指令碼
package com.example.tests;
import java.util.regex.Pattern;
import java.util.concurrent.TimeUnit;
import org.junit.*;
import static org.junit.Assert.*;
import static org.hamcrest.CoreMatchers.*;
import org.openqa.selenium.*;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.support.ui.Select;
public class Test {
private WebDriver driver;
private String baseUrl;
private boolean acceptNextAlert = true;
private StringBuffer verificationErrors = new StringBuffer();
@Before
public void setUp() throws Exception {
driver = new FirefoxDriver();
baseUrl = "https://www.katalon.com/";
driver.manage().timeouts().implicitlyWait(30, TimeUnit.SECONDS);
}
@Test
public void test() throws Exception {
driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
driver.findElement(By.id("kw")).click();
driver.findElement(By.id("kw")).clear();
driver.findElement(By.id("kw")).sendKeys("掘金網");
driver.findElement(By.xpath("//div[@id='container']/div[2]/div")).click();
driver.findElement(By.linkText("掘金- juejin.im - 一個幫助開發者成長的社群")).click();
// ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重構整個研發專案,促進自動化運維DevOps的落地?");
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
driver.findElement(By.linkText("我是如何重構整個研發專案,促進自動化運維DevOps的落地?")).click();
}
@After
public void tearDown() throws Exception {
driver.quit();
String verificationErrorString = verificationErrors.toString();
if (!"".equals(verificationErrorString)) {
fail(verificationErrorString);
}
}
private boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
private boolean isAlertPresent() {
try {
driver.switchTo().alert();
return true;
} catch (NoAlertPresentException e) {
return false;
}
}
private String closeAlertAndGetItsText() {
try {
Alert alert = driver.switchTo().alert();
String alertText = alert.getText();
if (acceptNextAlert) {
alert.accept();
} else {
alert.dismiss();
}
return alertText;
} finally {
acceptNextAlert = true;
}
}
}
python程式碼量明細比java要少一點,但是本文講java語言實踐。
我們主要關注 java版 @Test註解的那個test方法
driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
driver.findElement(By.id("kw")).click();
driver.findElement(By.id("kw")).clear();
driver.findElement(By.id("kw")).sendKeys("掘金網");
driver.findElement(By.xpath("//div[@id='container']/div[2]/div")).click();
driver.findElement(By.linkText("掘金- juejin.im - 一個幫助開發者成長的社群")).click();
// ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重構整個研發專案,促進自動化運維DevOps的落地?");
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
driver.findElement(By.linkText("我是如何重構整個研發專案,促進自動化運維DevOps的落地?")).click();
可能很多人已經能看懂了
開啟百度
driver.findElement(By.id(“kw”)).click();
通過id定位到html標籤,然後點選click();清空文字框.clear();輸入 掘金網3個字 sendKeys(“掘金網”);
這裡我們看一下百度的搜尋框程式碼
<input type="text" class="s_ipt" name="wd" id="kw" maxlength="100" autocomplete="off">
driver.findElement(By.linkText(“掘金- juejin.im - 一個幫助開發者成長的社群”)).click();
單擊掘金網
通過linktext定位到標籤並點選。
後面通過div=juejin一層一層定位到input,最後點選進入文章。
認識html標籤
HTML <input>
標籤
<input>
標籤用於蒐集使用者資訊。
根據不同的 type 屬性值,輸入欄位擁有很多種形式。輸入欄位可以是文字欄位、複選框、掩碼後的文字控制元件、單選按鈕、按鈕等等。
<form action="form_action.asp" method="get">
First name: <input type="text" name="fname" />
Last name: <input type="text" name="lname" />
<input type="submit" value="Submit" />
</form>
HTML <a>
標籤
<a> 標籤定義超連結,用於從一張頁面連結到另一張頁面。
<a> 元素最重要的屬性是 href 屬性,它指示連結的目標。
HTML <div>
標籤
<div>
可定義文件中的分割槽或節(division/section)。
<div>
標籤可以把文件分割為獨立的、不同的部分。它可以用作嚴格的組織工具,並且不使用任何格式與其關聯。
如果用 id 或 class 來標記<div>
,那麼該標籤的作用會變得更加有效。
<div style="color:#00FF00">
<h3>This is a header</h3>
<p>This is a paragraph.</p>
</div>
…………
其他標籤不一一介紹,可在參考網站上意義看
認識css
這裡只講1個關鍵的,比如
<div class="css1 css2"> ********</div>
表示這個div同時使用了css1和css2樣式,只需要知道如果沒辦法在selenium上定位的這個div,可使用css名定位。
如果有興趣,可再看下其他css相關知識。
js基礎
這裡講2個關鍵
<a onclick="test()">test</a>
上述程式碼,點選a標籤會執行js中的test方法,當selenium無法定位到這個a標籤,可以直接呼叫test()方法。
可以寫簡單的js指令碼,彈窗程式碼:
alert("hello");
下載谷歌瀏覽器
下載谷歌瀏覽器,這裡可以使用63.0.3239.84版本。
目前來說,谷歌瀏覽器版本相容性還是不錯的。
下載selenium driver
可不下,本文github專案中包含
下載selenium webdriver
下載idea開發工具
這個比較複雜,建議在java開發人員指導下完成。
selenium
這個版本是簡易版,但足夠
最終效果
我們通過錄制selenium指令碼,編輯,提交到git庫,由jenkins自動化編譯出jar包,通過bat命令在任意一臺pc端執行(預設開發人員提交程式碼後自動執行所有模組)。按功能模組,測試專案,生成測試報告。對測試不通過的模組
最大化
driver.manage().window().maximize();
開啟頁面
driver.get("https://www.baidu.com");
定位元素
多個相同時,返回第一個,沒有找到會拋異常NoSuchElementException
WebElement element = driver.findElement(*);
當返回多個時:
List<WebElement> elements = driver.findElements(*);
定位元素方式
<input class="input_class input_class2" type="text" name="user-name" id="user-id" />
通過id定位
WebElement element = driver.findElement(By.id("user-id"));
通過name定位
WebElement element = driver.findElement(By.name("user-name"));
通過className定位
WebElement element = driver.findElement(By.className("input_class.input_class2"));
注意多個class用小數點隔開,也可以使用cssSelector定位
WebElement element = driver.findElement(By.cssSelector("input"));
通過linkText定位,如:
WebElement element = driver.findElement(By.linkText("我是如何重構整個研發專案,促進自動化運維DevOps的落地?"));
意思就是連結內容定位
通過partialLinkText定位,模糊內容定位,和上相似
WebElement element = driver.findElement(By.linkText("我是如何重構整個研發專案?"));
通過tagName定位
WebElement element = driver.findElement(By.tagName("form"));
通過xpath定位
WebElement element = driver.findElement(By.xpath("//input[@id='passwd-id']"));
這個最為複雜,最簡單的版本是
//標籤型別[@屬性名=屬性值]
但也可以定位第幾個
//input[4]
其中[]中還可以增加邏輯and or表示式
WebElement element = driver.findElement(By.xpath("//input[@type='text' and @name='user-name']"));
WebElement element = driver.findElement(By.xpath("//input[@type='text' or @name='user-name']"));
[]中也可以增加start-with、ends-with、contains,比如
WebElement element = driver.findElement(By.xpath("//input[start-with(@id,'user-')]"));
WebElement element = driver.findElement(By.xpath("//input[ends-with(@id,'user-')]"));
WebElement element = driver.findElement(By.xpath("//input[contains(@id,'user-')]"));
還可以 任意屬性名
WebElement element = driver.findElement(By.xpath("//input[@*='user-name']"));
單擊某個元素
.click()
清空input
.clear();
input中輸入內容
.sendKeys("掘金網");
如果是上傳附件,可直接sendKeys路徑
.sendKeys("c:\shao.png");
得到input內容
.getText();
下拉框
Select select = new Select(driver.findElement(By.id("frequency")));
select.selectByValue("1");
driver.findElement(By.id("validDays")).click();
select.selectByValue("a");
select.deselectAll();
select.deselectByValue("a");
select.deselectByVisibleText("");
select.getAllSelectedOptions();
select.getFirstSelectedOption();
單選框
WebElement radio=driver.findElement(By.id("radio"));
radio.click(); //選擇某個選項
radio.clear(); //清空選項
radio.isSelected(); //判斷某個單選項是否被選中
複選框
WebElement checkbox = driver.findElement(By.id("checkbox"));
checkbox.clear(); //清空選項
checkbox.isSelected(); //是否選中
判斷是否可點選
isEnabled()
alert框操作
Alert alert = driver.switchTo().alert();
alert.accept(); //確定
alert.dismiss(); //取消
iframe切換(重點)
可能很多老的專案都有iframe,錄製指令碼的時候正常錄製,可執行的時候,卻無法執行,這個時候,需要切換iframe
driver.switchTo().defaultContent(); //回到預設的頁面
driver.switchTo().frame("leftFrame"); //切換到某個iframe
切換iframe,結束後,記得切換回預設頁面。
driver.findElement(By.linkText("匯入模板")).click();
WebElement iframe = driver.findElement(By.id("layui-layer-iframe1"));
driver.switchTo().frame(iframe);
Thread.sleep(2000);
driver.findElement(By.linkText("引用")).click();
driver.findElement(By.xpath("//button[@type='submit']")).click();
driver.findElement(By.xpath("(//button[@type='button'])[3]")).click();
Thread.sleep(1000);
driver.findElement(By.linkText("學生")).click();
以上摘自專案程式碼,僅供參考
執行 js
JavascriptExecutor js = (JavascriptExecutor) driver;
js.executeScript("viewDetail('1f50555e409a4597a027ff415ce6c9b4','09','2018')");
執行內部viewDetail方法
延時操作(重要)
很多時候我們需要延時,這時使用
Thread.sleep(1000);//延時1000毫秒
許多錯誤是因為需要等待時間,嘗試增加一個延時,也許這個問題就過去了。
專案程式碼
假設,我們產品有多個環境,我們定義一個environments陣列,(當-1時,提示使用者輸入),有多個模組(當-1時,提示使用者輸入),最終程式碼如下,執行後,錯誤報告會通過郵件傳送到指定郵箱或者其他地方。
執行效果圖
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import webfunction.*;
import java.util.Scanner;
public class Main {
private static WebDriver driver;
private static String baseUrl;
private boolean acceptNextAlert = true;
/**
* 各個環境
* */
private static String[] environments = {"環境1", "環境2", "環境3", "環境4", "環境5", "環境6"};
/**
* 錯誤日誌
* */
private static StringBuffer verificationErrors = new StringBuffer();
/**
* 是否處於debug模式
*/
private static boolean debug = false;
/**
* -1為手動模式,否則為指定數字
* */
private static String environment = "-1";
/**
* -1為手動模式,否則為指定數字
* */
private static String methods = "-1";
public static void main(String[] args) throws Exception {
//引用火狐瀏覽器驅動
System.setProperty("webdriver.chrome.driver", "C:\\selenium\\chromedriver.exe");
//定義使用者名稱密碼
String uname, upw;
Scanner sc = new Scanner(System.in);
System.out.println("請選擇環境");
for (int i = 0; i < environments.length; i++) {
System.out.println(i + ":" + environments[i]);
}
if ("-1".equals(environment)) {
environment = sc.next();
}
System.out.println("請輸入需要測試的功能,英文逗號隔開");
if ("-1".equals(methods)) {
methods = sc.next();
}
driver = new ChromeDriver();
System.out.println("您選擇的是" + environments[Integer.valueOf(environment)]);
switch (environment) {
case "0":
baseUrl = "http://*.*.*.*/";
uname = "admin";
upw = "admin";
testManage(baseUrl, uname, upw, methods, driver);
break;
case "1":
baseUrl = "http://*.*.*.*/";
uname = "admin";
upw = "admin";
testManage(baseUrl, uname, upw, methods, driver);
break;
case "2":
//等等等……
break;
}
}
private static void testManage(String url, String uname, String upw, String methods, WebDriver driver) throws InterruptedException {
//先登入管理端
WebLogin.webLogin(driver, url, uname, upw);
//然後測試所有模組
String[] strArray = null;
strArray = methods.split(",");
for (int i = 0; i < strArray.length; i++) {
switch (strArray[i]) {
case "0":
try {
// 系統基礎管理 - 使用者管理 - 新增使用者
WebSystemManage.addnewUser(driver, url);
} catch (Exception e) {
verificationErrors.append("系統基礎管理 - 使用者管理 - 新增使用者 出錯");
log(e);
}
break;
case "1":
try {
// 系統基礎管理 - 使用者管理 - 編輯使用者
WebSystemManage.editUser(driver, url);
} catch (Exception e) {
System.out.println("系統基礎管理 - 使用者管理 - 編輯使用者 出錯");
log(e);
}
break;
default:
break;
}
}
report(verificationErrors);
}
private static void report(StringBuffer verificationErrors) {
//傳送郵件
}
/**
* 根據debug變數是否輸出日誌
* @param e
*/
private static void log(Exception e) {
if (debug) {
e.printStackTrace();
}
}
private static boolean isElementPresent(By by) {
try {
driver.findElement(by);
return true;
} catch (NoSuchElementException e) {
return false;
}
}
private static boolean isAlertPresent() {
try {
driver.switchTo().alert();
return true;
} catch (NoAlertPresentException e) {
return false;
}
}
private static String closeAlertAndGetItsText() {
try {
Alert alert = driver.switchTo().alert();
String alertText = alert.getText();
if (acceptNextAlert) {
alert.accept();
} else {
alert.dismiss();
}
return alertText;
} finally {
acceptNextAlert = true;
}
}
}
程式碼那麼多其實我們只關注 public static void main(String[] args) throws Exception {}內的內容,比如,我們想執行我們最初錄製的掘金指令碼,只需將那端我要求特別關注的程式碼放到裡面即可,具體程式碼如下:
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
public class Main {
private static WebDriver driver;
public static void main(String[] args) throws Exception {
//引用火狐瀏覽器驅動
System.setProperty("webdriver.chrome.driver", "C:\\selenium\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
//以下為Katalon Recorder錄製後的指令碼
driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
Thread.sleep(2000);
driver.findElement(By.id("kw")).click();
driver.findElement(By.id("kw")).clear();
driver.findElement(By.id("kw")).sendKeys("掘金網");
Thread.sleep(100);
driver.findElement(By.id("su")).click();
Thread.sleep(1000);
driver.findElement(By.xpath("//div[@id='container']/div[2]/div")).click();
driver.findElement(By.linkText("掘金- juejin.im - 一個幫助開發者成長的社群")).click();
Thread.sleep(3000);
// ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重構整個研發專案,促進自動化運維DevOps的落地?");
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
Thread.sleep(2000);
driver.findElement(By.linkText("我是如何重構整個研發專案,促進自動化運維DevOps的落地?")).click();
}
}
上述程式碼中註釋內是Katalon Recorder匯出的指令碼,但是我們增加了一些延時操作,selenium延時有很3種:普通sleep、顯示等待方式、隱式等待方式。這裡先簡單粗暴一下,用Thread.sleep(*);延時,比如開啟百度延時2秒、輸入“掘金網”延時100毫秒、搜尋後延時3秒…………
很遺憾,我們程式碼報錯:
大概意思說超時沒有找到那個搜尋框,由於各種各樣的原因,會導致我們在火狐瀏覽器中錄製的指令碼在java程式碼中的谷歌瀏覽器裡無法相容,這個時候我們需要去分析一下具體邏輯。
這裡是由於新視窗需要切換window,可使用下述程式碼切換(替換程式碼中// ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]這行即可)。
Set<String> windowHandles = driver.getWindowHandles();
String windowHandle = driver.getWindowHandle();
for (String handle : windowHandles) {
if (!handle.equals(driver.getWindowHandle())) {
driver.switchTo().window(handle);
break;
}
}
匯出的指令碼By.xpath(“//div[@id=’juejin’]/div[2]/div/header/div/nav/ul/li[2]/form/input”)這一句很複雜,我們試著簡化它。
<input data-v-5ce25e66="" maxlength="32" placeholder="搜尋掘金" class="search-input">
首先搜尋下search-input樣式,看該頁面是否只有一個search-input樣式。
果然search-input樣式只有一個標籤。
於是我們將
By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")
//改為
By.className("search-input")
最終程式碼
import org.openqa.selenium.*;
import org.openqa.selenium.chrome.ChromeDriver;
import java.util.Set;
public class Main {
private static WebDriver driver;
public static void main(String[] args) throws Exception {
//引用火狐瀏覽器驅動
System.setProperty("webdriver.chrome.driver", "C:\\selenium\\chromedriver.exe");
driver = new ChromeDriver();
driver.manage().window().maximize();
driver.get("https://www.baidu.com/index.php?tn=monline_3_dg");
Thread.sleep(2000);
driver.findElement(By.id("kw")).click();
driver.findElement(By.id("kw")).clear();
driver.findElement(By.id("kw")).sendKeys("掘金網");
Thread.sleep(100);
driver.findElement(By.id("su")).click();
Thread.sleep(1000);
driver.findElement(By.xpath("//div[@id='container']/div[2]/div")).click();
driver.findElement(By.linkText("掘金- juejin.im - 一個幫助開發者成長的社群")).click();
Thread.sleep(7000);
Set<String> windowHandles = driver.getWindowHandles();
String windowHandle = driver.getWindowHandle();
for (String handle : windowHandles) {
if (!handle.equals(driver.getWindowHandle())) {
driver.switchTo().window(handle);
break;
}
}
// ERROR: Caught exception [ERROR: Unsupported command [selectWindow | win_ser_1 | ]]
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).click();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).clear();
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys("我是如何重構整個研發專案,促進自動化運維DevOps的落地?");
driver.findElement(By.xpath("//div[@id='juejin']/div[2]/div/header/div/nav/ul/li[2]/form/input")).sendKeys(Keys.ENTER);
Thread.sleep(2000);
driver.findElement(By.linkText("我是如何重構整個研發專案,促進自動化運維DevOps的落地?")).click();
}
}
編譯打包
得到selenium.jar包,可複製到C:\selenium下,和chromedriver.exe同級。
輸入cmd命令
C:\Users\Administrator>cd C:\selenium
C:\selenium>java -jar selenium2.jar
github專案執行
為了防止有讀者沒有改maven庫映象,所以把lib包都放在專案中了。直接使用idea開啟,可能有些配置需要改,可參考
寫在最後
至此,一個基礎版的selenium框架就搭好了,後續,可以連線資料庫,從庫中隨機取出帳號,進行專案測試。也可以配合bat指令碼,實現自動化測試以及報告生成。