Seleniumの実行時間をJUnitのClassRuleアノテーションで高速化する


はじめに

Seleniumでテストしている時、テストメソッド単位でブラウザの起動/終了が行われるのが一般的(だと思っている)。
ただ、毎回ブラウザの再起動をすると実行時間がかなり伸びるので短縮したかった。

方法は色々あると思うが、今回はJUnit4のClassRuleアノテーションでやってみた。
ClassRuleで宣言すればWebDriverのnew/quitがテストクラス単位にできるので、それなりに短縮になる。

↓Rule/ClassRuleについては、こちらの方が分かりやすく纏めてくださっていました。
http://qiita.com/Chayata/items/dd31e22bca6df6c91793

実装

Ruleアノテーションを利用するには専用のクラスを実装し、テストメソッドのフィールドにする必要がある。
詳細はこちらのリポジトリ参照

Rule側

ExternalResouceを継承してクラスを実装し、クラスのフィールドとしてWebDriverを生成しておく。
Overrideしたafterメソッドがjunitの後処理になるので、WebDriverのquitをafterに実装する。

WebDriverRule.java
public class WebDriverRule extends ExternalResource {

    private WebDriver driver;
    public WebDriver getDriver() {
        return getInstance();
    }

    @Override
    protected void after() {
        this.driver.quit();
    }

    private WebDriver getInstance(){
        if(this.driver == null){
            this.driver = new ChromeDriver();
        }
        return this.driver;
    }
}

テスト実行側

実装したRuleクラスは @Rule@ClassRule の両方で使うことができそれぞれ以下のようになる。
@ClassRuleで宣言すると before/afterがクラス単位の前後処理に相当し(@BeforeClass@AfterClass
@Ruleで宣言すると before/afterがメソッド単位の前後処理に相当する(@setUp@tearDown

Test.java
public class classSample {
    @ClassRule
    public static WebDriverRule dr = new WebDriverRule();

    @Test
    public void test(){
        WebDriver d = dr.getDriver();
        d.get("https://www.google.co.jp/");
        WebElement el = d.findElement(By.cssSelector("input[aria-label='検索']"));
        el.sendKeys("chrome test.");
    }
}

比較


上側が@ClassRule、下側が@Ruleでの実装。 実行するテストは両方同じ。
サンプルで作ったテストクラスでは、10秒くらい差がある。
ClassRuleの場合はブラウザの起動が初回のテストメソッドのみなので、テストメソッドが多いほど効果がある。
テスト環境ではブラウザ起動に5秒程度かかっていた。

まとめ

テスト対象にもよるが、テストメソッド毎にブラウザ再起動するのは過剰な場合が多いので、こうしておくほうが好み。
ただ、テストメソッド間に依存関係が出来ても気づきずらいので(cookieに情報が残って偶然動くとか)注意は必要。