移除 AbstractEventListener、EventFiringWebDriver 與 WebDriverEventListener
分類
升級至 WebDriverListener 與 EventFiringDecorator
裝飾 webdriver
new EventFiringWebDriver(driver); // Old approach
new EventFiringDecorator().decorate(driver); // New approach
實作方法包裝器
有時您可能會需要使用自訂實作來處理底層裝飾方法的呼叫。例如,您可能想要使用自己的 findElement 實作來儲存來自網頁元素的元數據。裝飾器 (擴展 WebDriverDecorator 等) 可能會變得非常複雜,為了簡化,我們將擴展 EventFiringDecorator,因為我們希望使用單一裝飾器來處理所有 listener 事件。
public class WebDriverWrapper implements WebDriver {
private final WebDriver driver;
WebDriverWrapper(WebDriver driver) {
this.driver = driver;
}
// custom implementation goes here
@Override
public WebElement findElement(final By by) {
// custom implementation goes here
return driver.findElement(by);
}
}
public class testDecorator extends EventFiringDecorator<WebDriver> {
@Override
public Object call(Decorated<?> target, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if ("findElement".equals(methodName)) {
WebDriverWrapper newDriver = new WebDriverWrapper((WebDriver) target.getOriginal());
return newDriver.findElement((By) args[0]);
}
return super.call(target, method, args);
}
}
關於上述範例的一些注意事項,我們僅覆寫了 'general' call 方法,並針對每次呼叫檢查方法名稱。若不深入探討裝飾器,也可以覆寫類別實例的呼叫,以提供更精確的方法。為了展示更多功能,讓我們修改一下範例。我們可以修改 WebElement context,因為我們可能關心子元素和 WebDriver 找到的元素 (WebDriver 和 WebElement 都擴展了 SearchContext)。
public class WebElementWrapper implements WebElement {
private final WebElement element;
WebElementWrapper(WebElement element) {
this.element = element;
}
@Override
public WebElement findElement(final By by) {
// custom implementation goes here
return element.findElement(by);
}
}
public class WebElementDecorator extends EventFiringDecorator<WebDriver> {
@Override
public Decorated<WebElement> createDecorated(WebElement original) {
return new DefaultDecorated<>(original, this) {
@Override
public Object call(Method method, Object[] args) throws Throwable {
String methodName = method.getName();
if ("findElement".equals(methodName)) {
// custom implementation goes here
WebElementWrapper element = new WebElementWrapper(getOriginal());
return element.findElement((By) args[0]);
}
return super.call(method, args);
}
};
}
}
在上面的範例中,我們仍然採用非常類似的方法來覆寫 call 方法,但現在我們也針對 WebElement 實例。
註冊 Listener
new EventFiringWebDriver(driver).register(listener1).register(listener2); // Old approach
new EventFiringDecorator(listener1, listener2); // New approach
監聽事件
WebDriverListener 類別中一項提升生活品質的變更,是使用了 'default'。在 Java 中,default 關鍵字用於介面方法時,表示該方法具有預設實作。如果實作介面的類別選擇不覆寫該方法,它將繼承預設實作。這項變更允許拆分 listener,而無需實作您不需要或不關心的不必要方法。
使用 before/after 方法呼叫監聽特定事件
// Old approach
public class AlertListener implements WebDriverEventListener {
@Override
public void beforeAlertAccept(final WebDriver driver) {
// custom implementation goes here
}
// implement every method in interface
}
// New approach
public class AlertListener implements WebDriverListener {
@Override
public void beforeAccept(Alert alert) {
// custom implementation goes here
}
// does not need to implement every method in interface
}
監聽通用事件
一項引入的變更是能夠監聽通用事件。一個使用案例是在平行化測試套件中記錄資訊。現在有一種更簡單的替代方案,即覆寫一個方法呼叫,而不是建立一個 listener 並覆寫每個方法來新增簡單的日誌語句。以下我覆寫了 beforeAnyCall,但也存在 afterAnyCall,它也具有對裝飾方法的呼叫結果。
public class Listener implements WebDriverEventListener {
private static final Logger LOGGER = Logger.getLogger(Listener.class.getName());
@Override
public void beforeAnyCall(Object target, Method method, Object[] args) {
logger.debug("Thread: " + Thread.currentThread().getName() +
" | Method Name: " + method.getName() +
" | Method Args: " + Arrays.toString(args));
}
}
此外,還新增了監聽更具體的通用事件的功能。回到日誌記錄範例,beforeAnyCall 是除錯資訊或追蹤執行緒動作的好方法,但可能會產生過多雜訊。在相同的使用案例中,我們可能只關心 WebDriver 或 WebElement 呼叫。可以針對 WebDriver 和衍生物件 (WebElement、Alert 等) 的實例覆寫 before/after 事件。
public class Listener implements WebDriverEventListener {
private static final Logger LOGGER = Logger.getLogger(Listener.class.getName());
@Override
public void beforeAnyWebDriverCall(WebDriver driver, Method method, Object[] args) {
logger.debug("Thread: " + Thread.currentThread().getName() +
" | Method Name: " + method.getName() +
" | Method Args: " + Arrays.toString(args));
}
@Override
public void beforeAnyWebElementCall(WebElement element, Method method, Object[] args) {
logger.debug("Thread: " + Thread.currentThread().getName() +
" | Method Name: " + method.getName() +
" | Method Args: " + Arrays.toString(args));
}
}
以上是一些關於如何轉換程式碼的通用範例!祝您測試愉快!




