LoginSignup
2
2

Selenium3とSelenium4どちらでも動くように作ったJavaクラスをひとつのGradleタスクでテストする方法

Last updated at Posted at 2022-11-25

解決すべき問題

Webブラウザに表示されるHTMLベースのUIを自動化テストするコードをわたしはSeleniumをベースにたくさん作ってきました。ずっとSelenium3を使ってきたが、2021年10月にSelenium4が正式リリースされた。WebUI自動化テストを作る仕事を今後も続けるつもりだが、Selenium3と4に共通する基本的な使い方をすることが大半だろう。だから新しく作る自動化テストがSelenium3と4どちらでも動くようにしたいと考えた。いざ着手したらけっこう面倒だった。技術的問題と解決方法をここにメモします。

公式ドキュメントにSelenium3とSelenium4の違いについて説明がある。

APIが非互換的に変更された一つの例としてWebDriverWaitクラスのコンストラクタのシグナチャが変更されたことがあげられる。

// Selenium3 signature
new WebDriverWait(driver, 3)
                       // ^
        .until(ExpectedConditions.elementToBeClickable(By.cssSelector("#id")));

Selenium3では引数timeoutlong型とし、指定された値3を秒単位の値と解釈すると決めうちしていました。いっぽうSelenium4ではtimeoutパラメータがjava.time.Duration型に変更されました。

// Selenium4 signature
new WebDriverWait(driver, Duration.ofSeconds(3))
                       // ^^^^^^^^^^^^^^^^^^^^^
      .until(ExpectedConditions.elementToBeClickable(By.cssSelector("#id")));

Selenium4は引数timeoutlong型とするシグナチャを定義していません。だからSelenium3を前提に書いた自動化テストのコードはSelenium4ではコンパイル・エラーになります。

解決方法

Seleniumのバージョンの差異を吸収するヘルパクラスを作った

com.kazurayam.inspectus.selenium.WebDriverFormulasクラスを自作しました。このクラスをどう使うかというと次のようなJUnitテストを書きます。

WebDriverFormulasTest

        WebDriverFormulas formulas;
...
    @Test
    public void test_createWebDriverWait() {
        WebDriverWait wait = formulas.createWebDriverWait(driver, 3);
        assertNotNull(wait);
        assertTrue(wait instanceof WebDriverWait);
    }

WebDriverFormulasクラスのcreateWebDriverWait(WebDriver, long)メソッドを呼び出すことによってWebDriverWaitオブジェクトのインスタンスが生成されます。このメソッド呼び出しはSelenium3でもSelenium4でもどちらでも成功します。ここにトリックがあります。

createAWebDriverWait(WebDriver, long)メソッドの実装を読めばわかるように、JavaリフクションAPIを使ってSelenium3とSelenium4とどちらのバージョンのクラスライブラリが実行時に与えられているかを調べ、現に使える方を選んで安全にWebDriverWaitオブジェクトを生成しています。

Selenium3でユニットテストしSelenium4でもユニットテストしたい、どうやるか

com.kazurayam.inspectus.selenium.WebDriverFormulasクラスをJUnit5でユニットテストしようとしました。Gradleのbuild.gradleファイルをこう書いた。

plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

dependencies {
    implementation group: 'org.seleniumhq.selenium', name: 'selenium-java',
                version: '3.141.59'
    testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.9.1'
    testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.9.1'
}

tasks.withType(Test) {
    useJUnitPlatform()
}

上記でSeleniumのバージョン 3.141.59 を指定していることに注意。build.xmlをこう書いた上でコマンドラインでGradleのtestタスクを実行します。

$ gradle test

これでSelenium3を与えた環境でカスタムクラスがちゃんと動くことをテストできました。では次にSelenium4でも動くことをテストしましょう。読者諸兄にはもうおわかりでしょうが、build.xmlを書き直せばいい。

implementation group: 'org.seleniumhq.selenium', name: 'selenium-java',
        version: '4.6.0'       // <== '3.141.59'

そして前と同じく

$ gradle test

とやる。これでSelenium4でカスタムクラスが動くことをテストできました。

しかしbuild.gradleファイルをいちいち書き直すこのやり方はダサい。我慢ならない。

わたしはこうしたいと考えた。

$ gradle testSelenium

testSeleniumというカスタムなGradleタスクを作って実行すると、dependenciesの中にSelenium3を指定したJUnitテストが実行される。さらに続いてSelenium4を指定したJUnitタスクも実行される、というふうにしたいと考えた。Gradleをどうひねれば実現できるでしょうか?

あちこち探り試行錯誤した挙句、build.gradleファイルを次のように書いたら私の望み通りにGradleが動いてくれました。

plugins {
    id 'java'
}

repositories {
    mavenCentral()
}

dependencies {
    testImplementation group: 'org.junit.jupiter', name: 'junit-jupiter-api', version: '5.9.1'
    testRuntimeOnly group: 'org.junit.jupiter', name: 'junit-jupiter-engine', version: '5.9.1'
}

tasks.withType(Test) {
    useJUnitPlatform()
}

task testWithSelenium3(type: Test, dependsOn: compileTestJava) {
    dependencies {
        implementation implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', 
                      version: '3.141.59'
    }
        include '**/WebDriverFormulas*'
}

task testWithSelenium4(type: Test, dependsOn: compileTestJava) {
    dependencies {
        implementation implementation group: 'org.seleniumhq.selenium', name: 'selenium-java', 
                    version: '4.6.0'
    }
    include '**/WebDriverFormulas*'
}

task testSelenium(dependsOn: [testWithSelenium3, testWithSelenium4])

testWithSelenium3タスクとtestWithSelenium4をこのように書けばいいとわかるまでけっこう苦労しました。めでたしめでたし。

2
2
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2