NỘI DUNG BÀI HỌC

✅ Cài đặt và sử dụng Extent report

Nếu bạn chưa biết mô hình đối tượng trang (Page Object) thì trước khi bắt đầu bài viết này mình khuyên bạn nên xem lại bài viết mô hình POM trong Selenium Java của An. Tại vì những ví dụ sẽ chạy test case hoàn chỉnh nên An chạy code theo dạng page object cho nhanh á. Nội dung liên quan là TestListener


✅ Cài đặt Extent Report trong Selenium Java


Cấu trúc source tổng quát như này

[Selenium Java] Bài 33: Cài đặt và sử dụng Extent Report Allure Report | Anh Tester

Đầu tiên mình sẽ thêm thư viện Extent Report vào trong pom.xml

Bước 1: Thêm thư viện Extent Reports vào pom.xml trong Maven Project

<!-- https://mvnrepository.com/artifact/com.aventstack/extentreports -->
<dependency>
	<groupId>com.aventstack</groupId>
	<artifactId>extentreports</artifactId>
	<version>5.1.2</version>
</dependency>

Hoặc vào link này để download bản tùy ý:

https://mvnrepository.com/artifact/com.aventstack/extentreports

 

Bước 2: Thêm Extent Reports class

An đã tạo package "reports" và thêm 2 class bên dưới vào package đó.


+ ExtentReportManager Class:

import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.reporter.ExtentSparkReporter;

public class ExtentReportManager {

    private static final ExtentReports extentReports = new ExtentReports();

    public synchronized static ExtentReports getExtentReports() {
        ExtentSparkReporter reporter = new ExtentSparkReporter("reports/extentreport/extentreport.html");
        reporter.config().setReportName("Extent Report | Anh Tester");
        extentReports.attachReporter(reporter);
        extentReports.setSystemInfo("Framework Name", "Selenium Java | Anh Tester");
        extentReports.setSystemInfo("Author", "Anh Tester");
        return extentReports;
    }

}


Cái "reports/extentreport/extentreport.html" là đường dẫn xuất ra file html của report. Folder "reports" sẽ nằm ngoài cùng ngang cấp src.


+ ExtentTestManager Class:

import com.aventstack.extentreports.ExtentReports;
import com.aventstack.extentreports.ExtentTest;
import com.aventstack.extentreports.MediaEntityBuilder;
import com.aventstack.extentreports.Status;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;

import java.util.HashMap;
import java.util.Map;

public class ExtentTestManager {
    static Map<Integer, ExtentTest> extentTestMap = new HashMap<>();
    static ExtentReports extent = ExtentReportManager.getExtentReports();

    public static ExtentTest getTest() {
        return extentTestMap.get((int) Thread.currentThread().getId());
    }

    public static synchronized ExtentTest saveToReport(String testName, String desc) {
        ExtentTest test = extent.createTest(testName, desc);
        extentTestMap.put((int) Thread.currentThread().getId(), test);
        return test;
    }

    public static void addScreenshot(String message) {
        String base64Image = "data:image/png;base64,"
                + ((TakesScreenshot) DriverManager.getDriver()).getScreenshotAs(OutputType.BASE64);

        getTest().log(Status.INFO, message,
                MediaEntityBuilder.createScreenCaptureFromBase64String(base64Image).build());
    }

    public static void addScreenshot(Status status, String message) {
        String base64Image = "data:image/png;base64,"
                + ((TakesScreenshot) DriverManager.getDriver()).getScreenshotAs(OutputType.BASE64);

        getTest().log(status, message,
                MediaEntityBuilder.createScreenCaptureFromBase64String(base64Image).build());
    }

    public static void logMessage(String message) {
        getTest().log(Status.INFO, message);
    }

    public static void logMessage(Status status, String message) {
        getTest().log(status, message);
    }
}


Lưu ý: cái DriverManager.getDriver() có nghĩa là lấy giá trị driver hiện hành trong ThreadLocal. Nếu các bạn đã design theo kiểu nào thì lấy ra theo kiểu đó chứ không phải luôn như vậy nhé.

 

  • extentTestMap lưu giữ thông tin của id luồng và các cá thể ExtentTest.
  • Phiên bản ExtentReports được tạo bằng cách gọi phương thức createExtentReports () từ ExtentManager.
  • Tại phương thức saveToReport(), một phiên bản của ExtentTest đã được tạo và đưa vào extentTestMap với id luồng hiện tại.
  • Tại phương thức getTest(), trả về cá thể ExtentTest trong scopeTestMap bằng cách sử dụng id luồng hiện tại.


Bước 3: Add report vào TestListener class

Chổ này bài trước mình học là tạo TestListener rồi đúng không. Nay mình chỉnh sửa lại chút.

import com.anhtester.helpers.CaptureHelper;
import com.anhtester.helpers.PropertiesHelper;
import com.anhtester.reports.ExtentReportManager;
import com.anhtester.reports.ExtentTestManager;
import com.anhtester.utils.LogUtils;

import com.aventstack.extentreports.Status;
import org.testng.ITestContext;
import org.testng.ITestListener;
import org.testng.ITestResult;

public class TestListener implements ITestListener {

    public String getTestName(ITestResult result) {
        return result.getTestName() != null ? result.getTestName() : result.getMethod().getConstructorOrMethod().getName();
    }

    public String getTestDescription(ITestResult result) {
        return result.getMethod().getDescription() != null ? result.getMethod().getDescription() : getTestName(result);
    }

    @Override
    public void onStart(ITestContext result) {
        PropertiesHelper.loadAllFiles();
        //Khởi tạo report (Extent và Allure)
    }

    @Override
    public void onFinish(ITestContext result) {
        LogUtils.info("End testing " + result.getName());

        //Kết thúc và thực thi Extents Report
        ExtentReportManager.getExtentReports().flush();
    }

    @Override
    public void onTestStart(ITestResult result) {
        LogUtils.info("Running test case " + result.getName());

        //Bắt đầu ghi 1 TCs mới vào Extent Report
        ExtentTestManager.saveToReport(getTestName(result), getTestDescription(result));
    }

    @Override
    public void onTestSuccess(ITestResult result) {
        LogUtils.info("Test case " + result.getName() + " is passed.");

        //Extent Report
        ExtentTestManager.logMessage(Status.PASS, result.getName() + " is passed.");
    }

    @Override
    public void onTestFailure(ITestResult result) {
        LogUtils.error("Test case " + result.getName() + " is failed.");
        //Screenshot khi fail
        //CaptureHelper.captureScreenshot(result.getName());
        LogUtils.error(result.getThrowable().toString());

        //Extent Report
        ExtentTestManager.addScreenshot(result.getName());
        ExtentTestManager.logMessage(Status.FAIL, result.getThrowable().toString());
        ExtentTestManager.logMessage(Status.FAIL, result.getName() + " is failed.");
    }

    @Override
    public void onTestSkipped(ITestResult result) {
        LogUtils.error("Test case " + result.getName() + " is skipped.");
        LogUtils.error(result.getThrowable().toString());

        //Extent Report
        ExtentTestManager.logMessage(Status.SKIP, result.getThrowable().toString());
    }

}


Còn cái LogUtils class thì mình đã thêm hôm trước trong bài ghi Logs vào file rồi nên dùng lại thôi nhen.

 

Bước 4: Gọi TestListener class vào test case

Chổ này thì mình có thể gọi 2 cấp độ class hoặc suite tùy ý như bài hôm trước về TestListener An đã nói rồi á. Có quên thì xem lại phát biết ngay nè.

Gọi trong BaseTest class:

[Selenium Java] Bài 33: Cài đặt và sử dụng Extent Report Allure Report | Anh Tester


Gọi trong Suite file XML:

[Selenium Java] Bài 31: Cài đặt và sử dụng Extent Report Allure Report | Anh Tester


Yeah vậy xong rồi đó. Chạy test case thôi nào.

Report sẽ xuất ra tại thư mục đường dẫn như mình chỉ định trên: "reports/extentreports/extentreport.html

[Selenium Java] Bài 33: Cài đặt và sử dụng Extent Report Allure Report | Anh Tester

Hoặc chúng ta mở file report html lên bằng cách click chuột phải chọn Open In -> Browser -> "Chrome hoặc Edge...tùy ý"

[Selenium Java] Bài 31: Cài đặt và sử dụng Extent Report Allure Report | Anh Tester


Report dạng Step kèm description nếu chúng ta có điền thuộc tính description vào @Test. Không có thì nó sẽ để trống. Bạn có thể custom nó ở class "TestListener" á.

[Selenium Java] Bài 33: Cài đặt và sử dụng Extent Report Allure Report | Anh Tester


Và như trong TestListener thì mình setup là test case nào Fail sẽ có Screenshot đi kèm á. Các bạn click chọn "base64 img" màu tím tím á nó sẽ hiển thị ngay.

[Selenium Java] Bài 33: Cài đặt và sử dụng Extent Report Allure Report | Anh Tester


Report dạng Chart khi click chọn option chart icon thứ 2 á.

[Selenium Java] Bài 33: Cài đặt và sử dụng Extent Report Allure Report | Anh Tester

Song song nó cũng ghi Log vào file cho mình luôn

[Selenium Java] Bài 31: Cài đặt và sử dụng Extent Report Allure Report | Anh Tester

Chúng ta có thể thêm các step auto vào report thông qua WebUI keyword hoặc một class nào đó bất kỳ chứa các action xử lý về auto cho test cases.

WebUI class:

import com.anhtester.reports.ExtentTestManager;
import com.anhtester.utils.LogUtils;

import com.aventstack.extentreports.Status;
import org.openqa.selenium.*;
import org.openqa.selenium.interactions.Actions;
import org.openqa.selenium.support.ui.ExpectedCondition;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.testng.Assert;

import java.time.Duration;
import java.util.List;

import static com.anhtester.drivers.DriverManager.getDriver;

public class WebUI {

    private static int EXPLICIT_WAIT_TIMEOUT = 10;
    private static int WAIT_PAGE_LEADED_TIMEOUT = 30;

    public static WebElement getWebElement(By by) {
        return getDriver().findElement(by);
    }

    public static void logConsole(String message) {
        System.out.println(message);
    }

    public static void hoverOnElement(By by) {
        waitForElementVisible(by);
        Actions action = new Actions(getDriver());
        action.moveToElement(getWebElement(by));
        LogUtils.info("Hover on element " + by);
        ExtentTestManager.logMessage(Status.PASS, "Hover on element " + by);
    }

    public static WebElement highLightElement(By by) {
        waitForElementVisible(by);
        // Tô màu border ngoài chính element chỉ định - màu đỏ (có thể đổi màu khác)
        if (getDriver() instanceof JavascriptExecutor) {
            ((JavascriptExecutor) getDriver()).executeScript("arguments[0].style.border='3px solid red'", getWebElement(by));
            sleep(1);
        }
        return getWebElement(by);
    }

    public static void rightClickElement(By by) {
        waitForElementVisible(by);
        Actions action = new Actions(getDriver());
        action.contextClick(getWebElement(by));
        LogUtils.info("Right click on element " + by);
        ExtentTestManager.logMessage(Status.PASS, "Right click on element " + by);
    }

    public static void openURL(String URL) {
        getDriver().get(URL);
        waitForPageLoaded();
        LogUtils.info("Open URL: " + URL);
        ExtentTestManager.logMessage(Status.PASS, "Open URL: " + URL);
    }

    public static String getCurrentUrl() {
        waitForPageLoaded();
        LogUtils.info("Get Current URL: " + getDriver().getCurrentUrl());
        ExtentTestManager.logMessage(Status.PASS, "Get Current URL: " + getDriver().getCurrentUrl());
        return getDriver().getCurrentUrl();
    }

    public static void clickElement(By by) {
        waitForElementVisible(by);
        highLightElement(by);
        getWebElement(by).click();
        LogUtils.info("Click on element " + by);
        ExtentTestManager.logMessage(Status.PASS, "Click on element " + by);
    }

    public static void setText(By by, String value) {
        waitForElementVisible(by);
        getWebElement(by).sendKeys(value);
        LogUtils.info("Set text " + value + " on element " + by);
        ExtentTestManager.logMessage(Status.PASS, "Set text " + value + " on element " + by);
    }

    public static String getTextElement(By by) {
        waitForElementVisible(by);
        LogUtils.info("Get text of element " + by);
        LogUtils.info("==> Text: " + getWebElement(by).getText());
        ExtentTestManager.logMessage(Status.PASS, "Get text of element " + by);
        ExtentTestManager.logMessage(Status.INFO, "==> Text: " + getWebElement(by).getText());
        return getWebElement(by).getText();
    }

    public static String getAttributeElement(By by, String attributeName) {
        waitForElementVisible(by);
        LogUtils.info("Get attribute value of element " + by);
        LogUtils.info("==> Attribute value: " + getWebElement(by).getAttribute(attributeName));
        ExtentTestManager.logMessage(Status.PASS, "Get attribute value of element " + by);
        ExtentTestManager.logMessage(Status.INFO, "==> Attribute value: " + getWebElement(by).getAttribute(attributeName));
        return getWebElement(by).getAttribute(attributeName);
    }

    public static void scrollToElementWithJS(By by) {
        waitForElementPresent(by);
        //Dùng Actions class
        //Robot class
        //Dùng JavascriptExecutor
        JavascriptExecutor js = (JavascriptExecutor) getDriver();
        js.executeScript("arguments[0].scrollIntoView(true);", getWebElement(by));
        logConsole("Scroll to element " + by);
    }

    public static void scrollToElement(By by) {
        //Dùng Actions class

    }

    public static void scrollToElementWithRobot(By by) {
        //Dùng Robot class

    }

    public static void sleep(double second) {
        try {
            Thread.sleep((long) (1000 * second));
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    public static void waitForElementVisible(By by, int second) {
        WebDriverWait wait = new WebDriverWait(getDriver(), Duration.ofSeconds(second), Duration.ofMillis(500));

        wait.until(ExpectedConditions.visibilityOfElementLocated(by));
    }

    public static void waitForElementVisible(By by) {
        WebDriverWait wait = new WebDriverWait(getDriver(), Duration.ofSeconds(EXPLICIT_WAIT_TIMEOUT), Duration.ofMillis(500));

        wait.until(ExpectedConditions.visibilityOfElementLocated(by));
    }

    public static void waitForElementPresent(By by, int second) {
        WebDriverWait wait = new WebDriverWait(getDriver(), Duration.ofSeconds(second));

        wait.until(ExpectedConditions.presenceOfElementLocated(by));
    }

    public static void waitForElementPresent(By by) {
        WebDriverWait wait = new WebDriverWait(getDriver(), Duration.ofSeconds(EXPLICIT_WAIT_TIMEOUT));

        wait.until(ExpectedConditions.presenceOfElementLocated(by));
    }

    public static void waitForElementClickable(By by, int second) {
        WebDriverWait wait = new WebDriverWait(getDriver(), Duration.ofSeconds(second));

        wait.until(ExpectedConditions.elementToBeClickable(by));
    }

    public static boolean verifyElementVisible(By by, int second) {
        try {
            WebDriverWait wait = new WebDriverWait(getDriver(), Duration.ofSeconds(second), Duration.ofMillis(500));
            wait.until(ExpectedConditions.visibilityOfElementLocated(by));
            return true;
        } catch (TimeoutException e) {
            e.printStackTrace();
            return false;
        }

    }

    public static boolean verifyElementNotVisible(By by, int second) {
        try {
            WebDriverWait wait = new WebDriverWait(getDriver(), Duration.ofSeconds(second), Duration.ofMillis(500));
            wait.until(ExpectedConditions.invisibilityOfElementLocated(by));
            return true;
        } catch (TimeoutException e) {
            e.printStackTrace();
            return false;
        }
    }

    public static boolean verifyElementNotPresent(By by, int second) {
        try {
            WebDriverWait wait = new WebDriverWait(getDriver(), Duration.ofSeconds(second), Duration.ofMillis(500));
            wait.until(ExpectedConditions.presenceOfElementLocated(by));
            return false;
        } catch (Exception e) {
            return true;
        }
    }

    public static boolean checkElementExist(By by) {
        List<WebElement> listElement = getDriver().findElements(by);

        if (listElement.size() > 0) {
            System.out.println("Element " + by + " existing.");
            return true;
        } else {
            System.out.println("Element " + by + " NOT exist.");
            return false;
        }
    }

    public static Boolean checkElementExist(String xpath) {
        List<WebElement> listElement = getDriver().findElements(By.xpath(xpath));

        if (listElement.size() > 0) {
            System.out.println("Element " + xpath + " existing.");
            return true;
        } else {
            System.out.println("Element " + xpath + " NOT exist.");
            return false;
        }
    }

    /**
     * Wait for Page loaded
     * Chờ đợi trang tải xong (Javascript tải xong)
     */
    public static void waitForPageLoaded() {
        WebDriverWait wait = new WebDriverWait(getDriver(), Duration.ofSeconds(WAIT_PAGE_LEADED_TIMEOUT), Duration.ofMillis(500));
        JavascriptExecutor js = (JavascriptExecutor) getDriver();

        //Wait for Javascript to load
        ExpectedCondition<Boolean> jsLoad = new ExpectedCondition<Boolean>() {
            @Override
            public Boolean apply(WebDriver driver) {
                return js.executeScript("return document.readyState").toString().equals("complete");
            }
        };

        //Check JS is Ready
        boolean jsReady = js.executeScript("return document.readyState").toString().equals("complete");

        //Wait Javascript until it is Ready!
        if (!jsReady) {
            System.out.println("Javascript is NOT Ready.");
            //Wait for Javascript to load
            try {
                wait.until(jsLoad);
            } catch (Throwable error) {
                error.printStackTrace();
                Assert.fail("FAILED. Timeout waiting for page load.");
            }
        }
    }

}


Trên là An thêm vào 5 hàm cơ bản: Open URL, clickElement, setText, getElementText, verifyEquals

Các bạn có thể thêm nữa nhen.

Khi chạy sẽ có kết quả như sau:

[Selenium Java] Bài 33: Cài đặt và sử dụng Extent Report Allure Report | Anh Tester


Xem tham khảo tại đây: https://github.com/anhtester/SeleniumTestNG092022Parallel/releases/tag/lesson_33_ExtentReport

Teacher

Teacher

Anh Tester

Software Quality Engineer

Đường dẫu khó chân vẫn cần bước đi
Đời dẫu khổ tâm vẫn cần nghĩ thấu

Cộng đồng Automation Testing Việt Nam:

🌱 Telegram Automation Testing:   Cộng đồng Automation Testing
🌱 
Facebook Group Automation: Cộng đồng Automation Testing Việt Nam
🌱 
Facebook Fanpage: Cộng đồng Automation Testing Việt Nam - Selenium
🌱 Telegram
Manual Testing:   Cộng đồng Manual Testing
🌱 
Facebook Group Manual: Cộng đồng Manual Testing Việt Nam

Chia sẻ khóa học lên trang

Bạn có thể đăng khóa học của chính bạn lên trang Anh Tester để kiếm tiền

Danh sách bài học