Seleniumで自動テストが失敗した時にハードコピーを取得する
webアプリのテストをselenium+Jenkinsで自動化していますが、seleniumのエラーレポートだけだと何が原因でエラーになったのか判断するのが難しいです。
そこで、テストが失敗した時に自動で画面のハードコピーを取得するようにしました。
まず、TestWatchクラスを継承したクラスを作成します。
public class SeleniumTestWatcher extends TestWatcher
静的初期化子を使って、テスト起動時に画像格納用のフォルダを作成するようにします。
Jenkinsから起動した場合とローカルでテストした場合で格納先を分けており、
Jenkinsから起動した場合はSystem.getProperty("BUILD_NUMBER"); でjenkinsのビルド番号を取得しています。
private WebDriver driver;
private static String imgpath;
static {
if(imgpath == null) {
File jenkins = new File("C:\\Program Files (x86)\\Jenkins");
// for server
if(jenkins.exists()) {
String buildnum = System.getProperty("BUILD_NUMBER");
imgpath = "【Jenkinsのworkspace】\\target\\error-img\\BUILD" + buildnum + "\\";
// for local
} else {
Date date = new Date();
Format fmt = new SimpleDateFormat("yyyyMMdd_HHmmss");
String time = fmt.format(date);
imgpath = "C:\\temp\\" + time + "\\";
}
File dir = new File(imgpath);
// フォルダがなかったら作成する
if (!dir.exists()) {
dir.mkdir();
}
}
}
failedメソッドをオーバーライドして、テストがfailになった時にスクリーンショットを撮るようにします。
// 失敗したときはスクリーンショットを撮る
@Override
protected void failed(Throwable e, Description description) {
super.failed(e, description);
String[] classname = description.getClassName().split("\\.");
try {
capAll(String.format("%s_%s",
classname[classname.length - 1], description.getMethodName()));
} catch (Exception e2) {
e2.printStackTrace();
}
}
スクリーンショットを取得するメソッドはこちら。
エラー等でアラートが出ているとスクリーンショットが撮れないのでアラートを閉じてから撮影するようにしています。
/**
* screenshotを取得する
* @param title
* @throws WebDriverException
* @throws IOException
*/
public void capture(String title) throws WebDriverException, IOException {
WebDriverWait wait = new WebDriverWait(driver, 3);
try {
Alert alert = wait.until(ExpectedConditions.alertIsPresent());
alert.accept();
} catch (TimeoutException e) {
}
String path = "";
path = imgpath + title +".png";
File file = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
FileUtils.copyFile(file, new File(path));
}
スクロールの発生するような画面で、画面全体のハードコピーを撮りたい場合はこちら。
自動でスクロールして一枚の画像として保存してくれます。
画面全体をスクロールする画面であればCSSセレクタは"body"でOK。
※JQueryを使う前提となっています。
/**
* screenshotを取得する
* @param title
* @throws WebDriverException
* @throws IOException
*/
public void capAll(String title) throws WebDriverException, IOException {
driver.switchTo().defaultContent();
TakesScreenshot ts = (TakesScreenshot) new Augmenter().augment(driver);
//JS実行用のExecuter
JavascriptExecutor jexec = (JavascriptExecutor) driver;
final String SCROLLAREA = "【スクロールエリアのcssセレクタ】";
// スクロールエリアのある画面
String isContent = String.valueOf(jexec.executeScript("return $('" + SCROLLAREA + "').length"));
if("1".equals(isContent)) {
//画面サイズで必要なものを取得
int innerH = Integer.parseInt(String.valueOf(jexec.executeScript("return $('" + SCROLLAREA + "').height()")));
int innerW =Integer.parseInt(String.valueOf(jexec.executeScript("return $('" + SCROLLAREA + "').width()")));
int scrollH = Integer.parseInt(String.valueOf(jexec.executeScript("return $('" + SCROLLAREA + "')[0].scrollHeight")));
int scrollW = Integer.parseInt(String.valueOf(jexec.executeScript("return $('" + SCROLLAREA + "')[0].scrollWidth")));
int windowH = Integer.parseInt(String.valueOf(jexec.executeScript("return window.innerHeight")));
int windowW = Integer.parseInt(String.valueOf(jexec.executeScript("return window.innerWidth")));
if(scrollW > innerW) {
windowH -= 12; // scrollbarの分
innerH -= 12;
}
if(scrollH > innerH) {
windowW -= 12; // scrollbarの分
innerW -= 12;
}
int headerH = windowH - innerH;
int headerW = windowW - innerW;
//イメージを扱うための準備
BufferedImage img = new BufferedImage(headerW + scrollW, headerH + scrollH, BufferedImage.TYPE_INT_ARGB);
Graphics g = img.getGraphics();
int j = 0;
int scrollableW = scrollW + innerW;
// 横スクロールのループ
while(scrollableW > innerW){
scrollableW -= innerW;
int scrollableH = scrollH + innerH;
int i = 0;
// 縦スクロールのループ
while(scrollableH > innerH){
scrollableH -= innerH;
// スクリーンショットを取得
BufferedImage imageParts = ImageIO.read(ts.getScreenshotAs(OutputType.FILE));
if(i == 0 && j == 0) {
// 1枚目は画面をそのまま貼る
g.drawImage(imageParts, windowW * j, windowH * i, null);
} else if(scrollableH <= innerH && scrollableW <= innerW) {
// 縦、横ともに最後は右下を埋めるように貼り付け
g.drawImage(imageParts, headerW + innerW * j, headerH + innerH * i, headerW + innerW * (j + 1), headerH + innerH * (i + 1),
windowW-scrollableW, windowH - scrollableH, windowW, windowH, null);
} else if(scrollableH <= innerH) {
// 縦スクロールの最後は下から埋めるように貼り付け
g.drawImage(imageParts, headerW + innerW * j, headerH + innerH * i, headerW + innerW * (j + 1), headerH + innerH * (i + 1),
headerW, windowH - scrollableH, windowW, windowH, null);
} else if(scrollableW <= innerW) {
// 横スクロール最後は右から埋めるように貼り付け
g.drawImage(imageParts, headerW + innerW * j, headerH + innerH * i, headerW + innerW * (j + 1), headerH + innerH * (i + 1),
windowW-scrollableW, headerH, windowW, windowH, null);
} else {
g.drawImage(imageParts, windowW * j, windowH * i, null);
// 途中の場合はscrollした分だけ貼る
//g.drawImage(imageParts, headerW + innerW * j, headerH + innerH * i, headerW + innerW * (j + 1), headerH + innerH * (i + 1),
// headerW, headerH, windowW, windowH, null);
}
// 縦に1画面分スクロール
i++;
jexec.executeScript("$('" + SCROLLAREA + "').animate({scrollTop:" + innerH * i + "});");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
// 縦スクロールが終わったら1回右にスクロールしてまた縦スクロール
j++;
jexec.executeScript("$('" + SCROLLAREA + "').animate({scrollTop: 0, scrollLeft:" + innerW * j + "});");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}
// 画像をファイルに出力する
String path = imgpath + title +".png";
ImageIO.write(img, "png", new File(path));
} else {
capture(title);
}
}
TestWatcherクラスが出来上がったら、
テストクラス内で上記で作成したクラスを@Ruleアノテーションをつけてインスタンス化します。
@Rule
public SeleniumTestWatcher watcher = new SeleniumTestWatcher();
すると、JUnitのテスト失敗時に日付_時刻フォルダの下に失敗時のハードコピーが保存されるようになります。
Jenkinsで「ビルド後の処理」の「成果物を保存」に以下のように書いておくとJenkins上から画像を確認できるようになります。
target/error-img/BUILD${BUILD_NUMBER}/*.png
「ビルドの成果物」に保存した画像が表示されるようになります。
クラス全体は一応githubに置いてあります。
https://github.com/widora99/seleniumTest
Author And Source
この問題について(Seleniumで自動テストが失敗した時にハードコピーを取得する), 我々は、より多くの情報をここで見つけました https://qiita.com/t-hashimoto/items/b7627d0efde6b9302e1f著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .