AbstractEventListener + EventFiringWebDriver + WebDriverEventListener の削除
カテゴリ
WebDriverListener および EventFiringDecorator へのアップグレード
WebDriver の装飾
new EventFiringWebDriver(driver); // Old approach
new EventFiringDecorator().decorate(driver); // New approach
メソッドラッパーの実装
装飾されたメソッド呼び出しの基盤として、独自のカスタム実装を使用する必要がある場合があります。例としては、Web 要素からメタデータを保存するために、独自の findElement 実装を使用したい場合があります。デコレータ(WebDriverDecorator などを拡張する)の深い迷路に迷い込む可能性がありますが、事を簡単にするために、すべてのリスナーイベントを処理する単一のデコレータが必要なため、EventFiringDecorator を拡張します。
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 メソッドのみをオーバーライドし、すべての呼び出しに対してメソッド名をチェックしています。デコレータについて深く掘り下げなくても、クラスインスタンスによる呼び出しをオーバーライドして、より的を絞ったアプローチを提供できます。さらにいくつかの機能を公開するために、例を変更してみましょう。子要素や WebDriver によって見つかった要素(WebDriver と WebElement はどちらも SearchContext を拡張します)が気になる可能性があるため、WebElement コンテキストを変更できます。
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 インスタンスもターゲットにしています。
リスナーの登録
new EventFiringWebDriver(driver).register(listener1).register(listener2); // Old approach
new EventFiringDecorator(listener1, listener2); // New approach
イベントのリスン
WebDriverListener クラスで特徴的なQoL(生活の質)の変更は、「default」の使用です。Java では、interface メソッドのコンテキストで使用される場合、default キーワードは、メソッドがデフォルト実装を持つことを示します。interface を実装するクラスがメソッドをオーバーライドしないことを選択した場合、デフォルト実装を継承します。この変更により、不要なメソッドや気にしないメソッドを実装する必要なく、リスナーを分割できます。
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
}
ジェネリックイベントのリスン
もたらされた変更の1つは、ジェネリックイベントをリッスンする機能です。ユースケースの1つは、並列化されたテストスイートでの情報ロギングです。リスナーを作成し、すべてのメソッドをオーバーライドして簡単なログステートメントを追加するのではなく、1つのメソッド呼び出しをオーバーライドするというより簡単な代替手段ができました。以下では 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));
}
}
以上が、コードを移行する方法に関する一般的な例です。ハッピーテスティング!