追記: この記事ではJSCoverをプロキシモードで利用する方法を説明したが,いくつかのアプリケーションで,動作が不安定な場合(レスポンスが帰ってこない)ことがあった.過去にはこういうissueもあったようだが,関連はわからない.JavaScriptがサーバ側で動的に生成されるのでなければ,file-systemモードなどを利用するほうが安心かもしれない
Selenium WebDriverですでに書かれたテストが存在するときに,JavaScriptのカバレッジを記録したい.
JSCoverとは
Javaで書かれたJavaScriptのカバレッジ測定用プログラム.以前はJSCoverageというものが有名だったが,現在はJSCoverに引き継がれたっぽい.公式サンプルがgithubにあるが,要点をここにまとめておく.
導入
pom.xmlに以下のdependencyを追加する
<dependency>
<groupId>com.github.tntim96</groupId>
<artifactId>JSCover</artifactId>
<version>1.0.6</version>
<scope>test</scope>
</dependency>
ついでにJUnitとSelenium (WebDriver)も導入しておく
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>2.38.0</version>
<scope>test</scope>
</dependency>
方針
JSCoverの使い方もいろいろあるっぽい( 公式ドキュメント )が,今回はプロキシモードを利用する.JSCover自体がプロキシの働きをして,テスト時に動的にカバレッジ測定用にJavaScriptを書き換えてくれる.
- JSCoverをプロキシとして起動
- WebDriverが上のプロキシを利用する用に設定
- テストを行い,JSCoverの画面を自動操作してカバレッジ測定結果をHTML形式で保存
※ 以下のサンプルでは簡単のため常にカバレッジを計測しているが,実際の運用ではフラグなどを立てて必要な時だけカバレッジを図るようにしたほうがパフォーマンス上好ましいかも知れない
JSCoverをプロキシとして起動
private static Thread server;
// JSCover起動用オプション
// 3129ポートを利用してプロキシとして起動する
private String[] args = new String[]{
"-ws",
"--port=3129",
"--proxy",
"--local-storage",
// カバレッジ測定除外設定,今回はjquery関係のファイルは無視
"--no-instrument-reg=.*jquery.*",
"--report-dir=" + getReportDir()
};
protected String[] getArgs() {
return args;
}
@Before
public void setUp() throws IOException {
File jsonFile = new File("js-cover-report/jscoverage.json");
if (jsonFile.exists())
jsonFile.delete();
// プロキシサーバの遅延初期化
if (server == null) {
server = new Thread(new Runnable() {
public void run() {
try {
Main.main(getArgs());
} catch (IOException e) {
throw new RuntimeException("Err", e);
}
}
});
server.start();
}
}
WebDriverが上のプロキシを利用する用に設定
private static WebDriver driver = getInstrumentedDriver();
// JSCoverプロキシを利用する用設定したFirefoxDriverインスタンスの取得
public static WebDriver getInstrumentedDriver() {
Proxy proxy = new Proxy().setHttpProxy("localhost:3129");
DesiredCapabilities cap = new DesiredCapabilities();
cap.setCapability(CapabilityType.PROXY, proxy);
return new FirefoxDriver(cap);
}
テストを行い,JSCoverの画面を自動操作してカバレッジ測定結果をHTML形式で保存
@Test
public void awesomeTestAndSaveJSCoverage() {
driver.get("http://localhost/your_test_target");
/* 何かしらのテスト */
// JSCoverのカバレッジ一覧ページを開く
driver.get("http://localhost/jscoverage.html");
// 画面を自動で操作して"Store Report"ボタンを押下,カバレッジ測定結果を記録する
new WebDriverWait(driver, /* 最大2秒待つ,この値は適当 */ 2).until(
ExpectedConditions.elementToBeClickable(By.id("storeTab"))).click();
new WebDriverWait(driver, 2).until(
ExpectedConditions.elementToBeClickable(By.id("storeButton"))).click();
new WebDriverWait(driver, 2).until(
ExpectedConditions.textToBePresentInElement(By.id("storeDiv"), "Coverage data stored at"));
// 測定結果をWebDriverで開く
driver.get("file:///" + new File(getReportDir() + "/jscoverage.html").getAbsolutePath());
// この先は人間が見てもいいし,WebDriverを使ってさらに自動化しても良い
}
上記を合わせたコードをhttps://gist.github.com/daisy1754/8002254 においておく.