การรอโดยนัยและการรอโดยชัดแจ้งใน Selenium ด้วยไวยากรณ์
⚡ สรุปอย่างชาญฉลาด
Selenium คำสั่ง Wait จะซิงโครไนซ์สคริปต์อัตโนมัติกับพฤติกรรมของหน้าเว็บแบบไดนามิก ป้องกันความล้มเหลวในการทดสอบที่เกิดจากองค์ประกอบที่โหลดแบบอะซิงโครนัส เอกสารอ้างอิงนี้อธิบายกลยุทธ์ Implicit, Explicit และ Fluent Wait พร้อมด้วยไวยากรณ์ของ WebDriver และวิธีการใช้งาน Java ตัวอย่างโค้ด และคำแนะนำเชิงปฏิบัติเกี่ยวกับการเลือกช่วงเวลาการรอที่เหมาะสม เพื่อให้การทดสอบทำงานได้อย่างเสถียรและเชื่อถือได้

In Seleniumคำสั่ง "รอ" มีบทบาทสำคัญในการดำเนินการทดสอบที่น่าเชื่อถือ ในบทเรียนนี้ คุณจะได้เรียนรู้ประเด็นสำคัญและความแตกต่างระหว่างคำสั่งรอแบบโดยปริยาย (Implicit Wait) และแบบโดยชัดแจ้ง (Explicit Wait) Seleniumพร้อมทั้งวิธีการใช้งาน Fluent Wait ในทางปฏิบัติ
ทำไมเราต้องรอเข้า Selenium?
แอปพลิเคชันเว็บสมัยใหม่ส่วนใหญ่พัฒนาขึ้นโดยใช้ อาแจ็กซ์ และ Javaต้นฉบับเมื่อเบราว์เซอร์โหลดหน้าเว็บ องค์ประกอบที่เราต้องการโต้ตอบด้วยอาจโหลดในเวลาที่ต่างกัน
นอกจากจะทำให้การระบุองค์ประกอบทำได้ยากแล้ว หากไม่สามารถระบุตำแหน่งขององค์ประกอบได้ทันเวลา... Selenium จะโยน องค์ประกอบ NotVisibleException. Selenium การรอช่วยแก้ปัญหาการซิงโครไนซ์นี้โดยการกำหนดช่วงเวลาให้ WebDriver ใช้ในการค้นหาองค์ประกอบก่อนที่จะเกิดข้อผิดพลาด
ลองพิจารณาสถานการณ์ที่ใช้ทั้งการรอแบบโดยปริยายและการรอแบบโดยชัดแจ้งในการทดสอบเดียวกัน สมมติว่าการรอแบบโดยปริยายตั้งไว้ที่ 20 วินาที และการรอแบบโดยชัดแจ้งตั้งไว้ที่ 10 วินาที
หากเรากำลังมองหาองค์ประกอบที่อยู่ภายใต้การควบคุมของบางสิ่งบางอย่าง เงื่อนไขที่คาดหวัง (การรอแบบระบุชัดเจน) และหากไม่พบองค์ประกอบภายในช่วงเวลา 10 วินาทีที่กำหนดไว้ WebDriver จะเปลี่ยนไปใช้ช่วงเวลา 20 วินาทีโดยปริยายก่อนที่จะแสดงข้อผิดพลาด องค์ประกอบ NotVisibleException.
Selenium WebDriver Waits
- รอโดยปริยาย
- รออย่างชัดแจ้ง
- รอได้อย่างคล่องแคล่ว
รอเข้าโดยปริยาย Selenium
การขอ รอเข้าโดยปริยาย Selenium คำสั่งนี้จะสั่งให้ WebDriver รอเป็นระยะเวลาที่กำหนดก่อนที่จะโยนข้อยกเว้น NoSuchElementException ค่าเริ่มต้นคือ 0 เมื่อตั้งค่าแล้ว WebDriver จะตรวจสอบ DOM ในระหว่างระยะเวลานั้นก่อนที่จะล้มเหลว Selenium WebDriver สืบทอดแนวคิดเรื่องการรอโดยปริยายมาจาก Watir.
ในตัวอย่างด้านล่าง เราประกาศการรอแบบไม่ระบุระยะเวลา (implicit wait) เป็นเวลา 10 วินาที หากไม่พบองค์ประกอบภายในช่วงเวลาดังกล่าว จะเกิดข้อผิดพลาดขึ้น
ไวยากรณ์การรอโดยปริยาย (Selenium 4):
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
package guru.test99;
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.testng.annotations.Test;
public class AppTest {
protected WebDriver driver;
@Test
public void guru99tutorials() throws InterruptedException {
driver = new ChromeDriver();
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
String eTitle = "Demo Guru99 Page";
String aTitle = "";
// launch Chrome and redirect it to the Base URL
driver.get("https://demo.guru99.com/test/guru99home/");
// Maximize the browser window
driver.manage().window().maximize();
// get the actual value of the title
aTitle = driver.getTitle();
// compare the actual title with the expected title
if (aTitle.equals(eTitle)) {
System.out.println("Test Passed");
} else {
System.out.println("Test Failed");
}
// close browser
driver.close();
}
}
คำอธิบายของ Code
ในตัวอย่างข้างต้น ลองพิจารณาข้อความต่อไปนี้:
driver.manage().timeouts().implicitlyWait(Duration.ofSeconds(10));
Selenium 4. แทนที่รูปแบบการรับพารามิเตอร์แบบเดิมที่มีสองอาร์กิวเมนต์ (จำนวนเต็มบวกหน่วยเวลา) ด้วยอาร์กิวเมนต์ Duration เพียงตัวเดียว คลาส Duration รองรับหน่วยเวลาต่างๆ เช่น วินาที นาที มิลลิวินาที และหน่วยเวลาอื่นๆ ผ่านตัวช่วยแบบคงที่ เช่น Duration.ofSeconds, Duration.ofMillis และ Duration.ofMinutes
รออย่างชัดแจ้ง Selenium
การขอ รออย่างชัดแจ้ง Selenium คำสั่งนี้จะสั่งให้ WebDriver รอตามเงื่อนไขที่กำหนด (เงื่อนไขที่คาดหวัง) หรือระยะเวลาสูงสุดก่อนที่จะโยนข้อยกเว้น ElementNotVisibleException การรอแบบนี้ฉลาดกว่าเพราะจะใช้ได้เฉพาะกับองค์ประกอบที่ระบุไว้เท่านั้น การรอแบบระบุชัดเจน (Explicit Wait) เป็นที่นิยมมากกว่าการรอแบบไม่ระบุชัดเจน (Implicit Wait) เมื่อใดก็ตามที่การทดสอบจำเป็นต้องจัดการกับเนื้อหา Ajax ที่โหลดแบบไดนามิก
เมื่อมีการประกาศการรอแบบชัดเจนแล้ว คุณจะต้องใช้ เงื่อนไขที่คาดหวังหรือคุณสามารถกำหนดความถี่ในการตรวจสอบได้โดยใช้ รอได้อย่างคล่องแคล่ว. หลีกเลี่ยงการใช้ Thread.sleep()เนื่องจากเป็นการหยุดการทำงานโดยไม่มีเงื่อนไข และโดยทั่วไปถือว่าเป็นวิธีปฏิบัติที่ไม่ดี
ในตัวอย่างด้านล่าง เราสร้างการอ้างอิงของ เว็บไดร์เวอร์รอสักครู่ คลาส สร้างอินสแตนซ์ด้วย ไดรเวอร์เว็บ อ้างอิง และตั้งค่าช่วงเวลาสูงสุดเป็น 20 วินาที
ไวยากรณ์การรอแบบชัดเจน (Selenium 4):
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20));
package guru.test99;
import java.time.Duration;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.annotations.Test;
public class AppTest2 {
protected WebDriver driver;
@Test
public void guru99tutorials() throws InterruptedException {
driver = new ChromeDriver();
WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(20));
String eTitle = "Demo Guru99 Page";
String aTitle = "";
// launch Chrome and redirect it to the Base URL
driver.get("https://demo.guru99.com/test/guru99home/");
// Maximize the browser window
driver.manage().window().maximize();
// get the actual value of the title
aTitle = driver.getTitle();
// compare the actual title with the expected title
if (aTitle.contentEquals(eTitle)) {
System.out.println("Test Passed");
} else {
System.out.println("Test Failed");
}
WebElement guru99seleniumlink;
guru99seleniumlink = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.xpath("/html/body/div[1]/section/div[2]/div/div[1]/div/div[1]/div/div/div/div[2]/div[2]/div/div/div/div/div[1]/div/div/a/i")));
guru99seleniumlink.click();
}
}
คำอธิบายของ Code
พิจารณารหัสต่อไปนี้:
WebElement guru99seleniumlink;
guru99seleniumlink = wait.until(ExpectedConditions.visibilityOfElementLocated(
By.xpath("/html/body/div[1]/section/div[2]/div/div[1]/div/div[1]/div/div/div/div[2]/div[2]/div/div/div/div/div[1]/div/div/a/i")));
guru99seleniumlink.click();
ในตัวอย่าง WebDriverWait นี้ สคริปต์จะรอสูงสุด 20 วินาที ตามที่กำหนดไว้ เว็บไดร์เวอร์รอสักครู่ ชั้นเรียน จนกระทั่ง เงื่อนไขที่คาดหวัง พึงพอใจ — แล้วแต่ว่าเหตุการณ์ใดเกิดขึ้นก่อน
ดังกล่าวข้างต้น Java โค้ดจะรอเงื่อนไขนานสูงสุด 20 วินาที การมองเห็นขององค์ประกอบที่ตั้งอยู่ จะเป็นจริง
เงื่อนไขที่คาดหวังต่อไปนี้สามารถนำไปใช้ได้ Selenium การรอแบบชัดเจน:
- alertIsPresent ()
- elementSelectionStateToBe()
- องค์ประกอบToBeClickable()
- องค์ประกอบToBeSelected()
- frameToBeAvailableAndSwitchToIt()
- การมองไม่เห็นขององค์ประกอบที่ตั้ง ()
- การมองไม่เห็นขององค์ประกอบด้วยข้อความ ()
- การแสดงตนขององค์ประกอบทั้งหมดตั้งอยู่โดย ()
- การแสดงตนขององค์ประกอบตั้งอยู่()
- textToBePresentInElement()
- textToBePresentInElementlocation()
- textToBePresentInElementValue()
- ชื่อเรื่องคือ()
- ชื่อเรื่องมี()
- การมองเห็นของ()
- การมองเห็นขององค์ประกอบทั้งหมด ()
- การมองเห็นขององค์ประกอบทั้งหมดตั้งอยู่โดย ()
- การมองเห็นขององค์ประกอบตั้งอยู่()
รอเข้าได้เลย Selenium
การขอ รอเข้าได้เลย Selenium กำหนดระยะเวลาสูงสุดที่ WebDriver จะรอเงื่อนไข พร้อมทั้งความถี่ในการตรวจสอบเงื่อนไขก่อนที่จะโยนข้อยกเว้น ElementNotVisibleException Fluent Wait จะตรวจสอบองค์ประกอบเป็นระยะๆ จนกว่าจะพบวัตถุหรือหมดเวลา
ความถี่: วงจรการทำซ้ำเพื่อประเมินสภาพเป็นระยะๆ
ลองพิจารณาสถานการณ์ที่องค์ประกอบหนึ่งโหลดในช่วงเวลาที่ไม่แน่นอน องค์ประกอบนั้นอาจโหลดใน 10 วินาที 20 วินาที หรือนานกว่านั้น หากเรากำหนดการรอแบบชัดเจนไว้ที่ 20 วินาที สคริปต์จะรอจนครบระยะเวลาที่กำหนดก่อนที่จะล้มเหลว ในกรณีเช่นนี้ Fluent Wait เป็นตัวเลือกที่เหมาะสมที่สุด เพราะมันจะตรวจสอบสถานะตามความถี่ที่ระบุไว้จนกว่าจะพบองค์ประกอบนั้น หรือจนกว่าตัวจับเวลาสุดท้ายจะหมดเวลา
ไวยากรณ์การรอแบบ Fluent (Selenium 4):
Wait<WebDriver> wait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(30))
.pollingEvery(Duration.ofSeconds(5))
.ignoring(NoSuchElementException.class);
รูปแบบการลงนามแบบเก่าที่รับค่าจำนวนเต็มและหน่วยเวลาถูกยกเลิกแล้วใน Selenium 3.11 และถูกลบออกใน Selenium 4. API ที่อิงตามระยะเวลาดังที่แสดงด้านบน เป็นแนวทางที่แนะนำในปัจจุบัน
package guru.test99;
import java.time.Duration;
import java.util.NoSuchElementException;
import java.util.function.Function;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.support.ui.FluentWait;
import org.openqa.selenium.support.ui.Wait;
import org.testng.annotations.Test;
public class AppTest3 {
protected WebDriver driver;
@Test
public void guru99tutorials() throws InterruptedException {
String eTitle = "Demo Guru99 Page";
String aTitle = "";
driver = new ChromeDriver();
// launch Chrome and redirect it to the Base URL
driver.get("https://demo.guru99.com/test/guru99home/");
// Maximize the browser window
driver.manage().window().maximize();
// get the actual value of the title
aTitle = driver.getTitle();
// compare the actual title with the expected title
if (aTitle.contentEquals(eTitle)) {
System.out.println("Test Passed");
} else {
System.out.println("Test Failed");
}
Wait<WebDriver> wait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(30))
.pollingEvery(Duration.ofSeconds(5))
.ignoring(NoSuchElementException.class);
WebElement clickseleniumlink = wait.until(new Function<WebDriver, WebElement>() {
public WebElement apply(WebDriver driver) {
return driver.findElement(By.xpath("/html/body/div[1]/section/div[2]/div/div[1]/div/div[1]/div/div/div/div[2]/div[2]/div/div/div/div/div[1]/div/div/a/i"));
}
});
// click on the selenium link
clickseleniumlink.click();
// close browser
driver.close();
}
}
คำอธิบายของ Code
พิจารณารหัสต่อไปนี้:
Wait<WebDriver> wait = new FluentWait<>(driver)
.withTimeout(Duration.ofSeconds(30))
.pollingEvery(Duration.ofSeconds(5))
.ignoring(NoSuchElementException.class);
ในตัวอย่างข้างต้น เราประกาศ Fluent Wait โดยตั้งค่าหมดเวลาไว้ที่ 30 วินาที ความถี่ในการตรวจสอบทุก 5 วินาที และไม่สนใจ NoSuchElementException.
พิจารณารหัสต่อไปนี้:
public WebElement apply(WebDriver driver) {
return driver.findElement(By.xpath("/html/body/div[1]/section/div[2]/div/div[1]/div/div[1]/div/div/div/div[2]/div[2]/div/div/div/div/div[1]/div/div/a/i"));
}
ฟังก์ชันนี้ระบุ WebElement บนหน้าเว็บ (ในที่นี้คือ Selenium (ลิงก์บนหน้าแรก) ด้วยช่วงเวลาการตรวจสอบ 5 วินาทีและการหมดเวลา 30 วินาที สคริปต์จะตรวจสอบหาองค์ประกอบทุกๆ 5 วินาทีเป็นเวลาสูงสุด 30 วินาที หากพบองค์ประกอบภายในช่วงเวลานั้น สคริปต์จะทำงานต่อไป มิเช่นนั้น สคริปต์จะแจ้งข้อผิดพลาด องค์ประกอบ NotVisibleException ถูกโยนทิ้ง
ยังตรวจสอบ: Selenium บทช่วยสอน IDE สำหรับผู้เริ่มต้น
ความแตกต่างระหว่างการรอโดยนัยกับการรออย่างชัดเจน
ตารางด้านล่างนี้แสดงให้เห็นถึงความแตกต่างที่สำคัญระหว่าง Implicit Wait และ Explicit Wait ใน Selenium.
| รอโดยปริยาย | รออย่างชัดแจ้ง |
|---|---|
| เวลาการรอโดยปริยายจะถูกนำไปใช้กับองค์ประกอบทั้งหมดในสคริปต์ | การกำหนดเวลาการรอแบบระบุชัดเจนจะใช้เฉพาะกับองค์ประกอบที่กำหนดเป้าหมายไว้โดยเฉพาะเท่านั้น |
| ใน Implicit Wait นั้น ExpectedConditions จะไม่ถูกระบุสำหรับองค์ประกอบดังกล่าว | ในโหมด Explicit Wait จะต้องกำหนด ExpectedConditions สำหรับองค์ประกอบนั้นด้วย |
| แนะนำให้ใช้เมื่อโหลดองค์ประกอบต่างๆ ภายในช่วงเวลาการรอโดยปริยายที่กำหนดไว้ | แนะนำให้ใช้เมื่อองค์ประกอบใช้เวลานานในการโหลด และเมื่อตรวจสอบสถานะขององค์ประกอบ เช่น visibilityOfElementLocated, elementToBeClickable หรือ elementToBeSelected |
| ตั้งค่าเพียงครั้งเดียวและนำไปใช้กับวงจรชีวิตของอินสแตนซ์ WebDriver | ตั้งค่าต่อองค์ประกอบหรือต่อการตรวจสอบแต่ละครั้ง เพื่อให้ควบคุมได้ละเอียดยิ่งขึ้น |
วิธีเลือกกลยุทธ์การรอคอยที่เหมาะสม
การเลือกคำสั่งรอที่ถูกต้องส่งผลโดยตรงต่อความเสถียรและเวลาในการประมวลผลของสคริปต์ ใช้กรอบการตัดสินใจนี้เพื่อเลือกตัวเลือกที่เหมาะสมสำหรับแต่ละสถานการณ์
- ระบุรูปแบบการรับน้ำหนัก: ตรวจสอบว่าองค์ประกอบนั้นปรากฏขึ้นในเวลาที่กำหนด หลังจากได้รับการตอบสนองจาก Ajax หรือในช่วงเวลาที่ไม่แน่นอน การโหลดแบบคงที่เหมาะกับ Implicit Wait ในขณะที่การโหลดที่ไม่แน่นอนเหมาะกับ Fluent Wait
- หลีกเลี่ยงการใช้การรอแบบ Implicit และ Explicit ปะปนกัน: การรวมทั้งสองอย่างเข้าด้วยกันอาจทำให้เกิดความล่าช้าที่ไม่คาดคิด เนื่องจากระยะเวลารอคอยที่ยาวนานกว่าอาจมีบทบาทสำคัญกว่า Selenium เอกสารแนะนำให้ใช้กลยุทธ์เพียงหนึ่งเดียวต่อเซสชัน WebDriver เท่านั้น
- ตั้งค่าเริ่มต้นเป็นการรอเนื้อหาแบบไดนามิกอย่างชัดเจน: เมื่อหน้าเว็บต้องอาศัย Ajax, การแสดงผลแบบมีเงื่อนไข หรือแอนิเมชัน Explicit Wait with ExpectedConditions จะกำหนดเป้าหมายไปยังองค์ประกอบที่สำคัญอย่างแม่นยำ
- ใช้ฟังก์ชัน Fluent Wait สำหรับการตั้งค่าเวลาที่เปลี่ยนแปลงได้: เมื่อเวลาในการโหลดองค์ประกอบแตกต่างกันระหว่างการทำงานแต่ละครั้ง ให้กำหนดค่า Fluent Wait โดยใช้ช่วงเวลาการตรวจสอบเป็นระยะ การตรวจสอบเป็นระยะจะช่วยลดเวลาการรอโดยรวมเมื่อเทียบกับการตั้งเวลาหมดอายุแบบยาวเพียงครั้งเดียว
- แทนที่ Thread.sleep: การกำหนดค่าการรอแบบตายตัวจะทำให้ชุดทดสอบทำงานช้าลงและซ่อนปัญหาเรื่องเวลาที่แท้จริง ควรแทนที่ด้วยการรอแบบมีเงื่อนไขเพื่อให้การทำงานรวดเร็วและแน่นอนยิ่งขึ้น
- ปรับค่าเวลาหมดอายุ: เริ่มต้นด้วยค่าหมดเวลาสั้นๆ (5-10 วินาที) และค่อยๆ เพิ่มค่าหมดเวลาเมื่อพบปัญหาที่แสดงให้เห็นถึงการโหลดที่ช้าลงอย่างแท้จริง ค่าหมดเวลาเริ่มต้นที่นานเกินไปจะบดบังประสิทธิภาพที่ลดลง
- เก็บค่าการรอไว้ในยูทิลิตี้ตัวช่วย: รวมตรรกะการรอคอยไว้ในคลาสตัวช่วย เพื่อให้การเปลี่ยนแปลงนโยบายการหมดเวลาใช้ได้กับชุดทดสอบทั้งหมด
ด้วยการปฏิบัติตามกรอบนี้ วิศวกรระบบอัตโนมัติสามารถสร้างสคริปต์ที่มีความยืดหยุ่นซึ่งปรับให้เข้ากับจังหวะเวลาของแอปพลิเคชันจริงได้โดยไม่ทำให้ระบบทำงานช้าหรือเปราะบาง
ข้อผิดพลาดทั่วไปที่ควรหลีกเลี่ยง Selenium รอ
แม้แต่ผู้ทดสอบที่มีประสบการณ์ก็ยังพลาดพลั้งในกับดักเล็กๆ น้อยๆ ที่เกิดขึ้นซ้ำๆ เมื่อทำงานกับ... Selenium การรอ การหลีกเลี่ยงปัญหาเหล่านี้จะช่วยให้สคริปต์ทำงานได้อย่างรวดเร็ว มีความแน่นอน และบำรุงรักษาได้ง่ายในทีมและสภาพแวดล้อมต่างๆ
ข้อผิดพลาดทั่วไปข้อแรกคือการใช้ Thread.sleep มากเกินไป การกำหนดเวลาหยุดแบบตายตัวจะบังคับให้สคริปต์รอจนครบระยะเวลาที่กำหนดโดยไม่คำนึงถึงความพร้อมใช้งานขององค์ประกอบจริง ซึ่งจะทำให้เวลาในการทำงานโดยรวมเพิ่มขึ้น ควรแทนที่การหยุดดังกล่าวด้วย Explicit Wait หรือ Fluent Wait เพื่อให้สคริปต์ดำเนินการต่อทันทีที่ตรงตามเงื่อนไข
ข้อผิดพลาดประการที่สองคือการผสมผสานการรอแบบ Implicit และ Explicit ในการทดสอบเดียวกัน กลไกทั้งสองอาจส่งผลซ้อนทับกัน ทำให้เกิดการหมดเวลาที่ไม่สามารถคาดเดาได้และยากต่อการแก้ไข เลือกใช้กลยุทธ์ใดกลยุทธ์หนึ่งต่อเซสชัน WebDriver และใช้กลยุทธ์นั้นอย่างสม่ำเสมอ
ข้อผิดพลาดประการที่สามคือการตั้งค่าหมดเวลาไว้สูงเกินไป “เผื่อไว้ก่อน” การตั้งค่าเวลาหมดเวลาเริ่มต้นที่ยาวนานจะซ่อนปัญหาด้านประสิทธิภาพที่แท้จริงและทำให้การตอบสนองในกระบวนการบูรณาการอย่างต่อเนื่องช้าลง ควรเริ่มต้นด้วยเวลาหมดเวลาที่สั้น และขยายเวลาหมดเวลาเฉพาะเมื่อบันทึกความล้มเหลวพิสูจน์ได้ว่ามีปัญหาด้านเวลาเกิดขึ้นจริง
ยังตรวจสอบ: Selenium บทช่วยสอนสำหรับผู้เริ่มต้น: เรียนรู้ WebDriver ใน 7 วัน
