Selenium에서 자동 테스트가 실패했을 때 하드 카피 얻기

8796 단어 JUnitJenkins셀레늄
웹 앱 테스트를 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 메서드를 재정의하여 테스트가 실패할 때 스크린샷을 찍도록 합니다.
// 失敗したときはスクリーンショットを撮る
@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에 있습니다.
htps : // 기주 b. 코 m / 우도라 99 / 세이 니 m st

좋은 웹페이지 즐겨찾기