全面了解Allure Report

一、What is Allure Report?

Allure Report是一個生成漂亮且易於閱讀的測試報告的工具。它能夠將測試結果和測試日誌以一種簡潔的方式呈現出來,支持多種編程語言和測試框架,如Java、Ruby、Python和C#等語言以及TestNG、JUnit和Pytest等框架。Allure Report對於提高測試效率和後續問題定位都非常有幫助。

二、Features of Allure Report

使用Allure Report有以下幾個優點和特點:

1、美觀、易讀:Allure Report的頁面效果非常精美,整個測試報告看起來是非常直觀且易於理解的。

2、靈活、易擴展:Allure Report支持多種編程語言和測試框架,而且還提供介面方便用戶自定義插件。

3、歷史報告:Allure Report支持歷史記錄,當運行了多個測試套件時,用戶可以輕鬆地查看哪些測試用例失敗或者哪些測試用例的性能不佳。

4、趨勢分析:Allure Report也提供了趨勢分析功能,用戶可以根據前幾次測試數據來分析軟體的穩定性和改進方向。

三、How to Generate Allure Report?

使用Allure Report,需要以下幾個步驟:

1、安裝Allure Report:可以使用命令行安裝,也可以使用IDE插件進行安裝。

npm install -g allure-commandline

2、集成Allure Report到測試框架中:Allure Report支持多種編程語言和測試框架,集成方式各不相同。

下面以Java語言和TestNG框架為例:

//pom.xml文件中添加以下配置:
<dependencies>
    <dependency>
        <groupId>io.qameta.allure</groupId>
        <artifactId>allure-testng</artifactId>
        <version>2.0-BETA16</version>
        <scope>test</scope>
    </dependency>
</dependencies>

//TestListener.java文件中添加以下內容:
public class TestListener extends TestListenerAdapter {
 
    @Override
    public void onTestSuccess(ITestResult result) {
        saveTextLog(getTestMethodName(result) + " Passed successfully!");
    }
 
    @Override
    public void onTestFailure(ITestResult result) {
        saveTextLog(getTestMethodName(result) + " Failed!");
        saveScreenshotPNG(driver);
    }
 
    @Override
    public void onTestSkipped(ITestResult result) {
        saveTextLog(getTestMethodName(result) + " Skipped!");
    }
}

//TestBase.java文件中添加以下內容:
@Listeners({TestListener.class})
public class TestBase{
    //code
}

3、運行測試用例並生成測試報告:在項目根目錄下運行以下命令即可生成測試報告

mvn clean test
allure serve allure-results

四、Customize Allure Report

Allure Report同樣提供自定義插件的功能。用戶可以根據自身需求添加額外的數據到測試報告中,比如Jenkins集成、執行時間、測試結果分類等。

下面以添加分類數據為例:

//pom.xml中添加以下配置:
<dependencies>
    <dependency>
        <groupId>io.qameta.allure</groupId>
        <artifactId>allure-testng</artifactId>
        <version>2.0-BETA16</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>io.qameta.allure</groupId>
        <artifactId>allure-java-commons</artifactId>
        <version>2.0-BETA16</version>
    </dependency>
</dependencies>

//Category.java文件:
public enum Category {
	SEARCH("Search"), LOGIN("Login"), CHECKOUT("Checkout"), PROMO("Promo");

    private String name;

    Category(String name) {
        this.name = name;
    }

    public String get() {
        return name;
    }
}
//CategoryAnnotation.java文件:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.TYPE;

@Retention(RetentionPolicy.RUNTIME)
@Target({METHOD, TYPE})
public @interface CategoryAnnotation {

    Category[] value();

    String[] component() default {};

}

//TestListener.java中添加以下內容:
public void setCategories(ITestResult result, Description description) {
        String[] categories = Arrays.stream(description.getAnnotations())
                .filter(a -> a.annotationType().equals(CategoryAnnotation.class))
                .map(a -> ((CategoryAnnotation) a).value())
                .flatMap(Arrays::stream).map(Category::get).toArray(String[]::new);
        if (categories.length != 0) {
            result.getTestContext().setAttribute("categories", categories);
        }
    }

/***
     * Description: 具體執行測試    
     * @param result
     */
    @Override
    public void onTestStart(ITestResult result) {
        String name = getTestMethodName(result);
        Category[] category = getCategory(result);
        StringBuilder builder = new StringBuilder();
        if (category != null) {
            builder.append("[");
            for (int i = 0; i < category.length; i++) {
                builder.append(category[i].get());
                if (i < category.length - 1) {
                    builder.append(",");
                }
            }
            builder.append("] ");
        }
        builder.append(name);
        log.info("Start test:" + builder.toString());
        Step step = new Step();
        step.setName(builder.toString());
        step.setStatus(Status.PASSED);
        Allure.getLifecycle().startStep(UUID.randomUUID().toString(),step);
    }

    /***
     * Description:獲取Method的category[Array]
     * @param result
     * @return
     */
    public Category[] getCategory(ITestResult result) {
        Description description = getDescription(result);
        if (description != null) {
            List annotationList = getDeclaredAnnotations(description);
            for (Annotation a : annotationList) {
                if (a instanceof CategoryAnnotation) {
                    return ((CategoryAnnotation) a).value();
                }
            }
        }
        return null;
    }

    /***
     * Description:獲取到當前的Case的Description
     * @param result
     * @return
     */
    public Description getDescription(ITestResult result) {
        Description description = null;
        try {
            Object instance = result.getInstance();
            if (instance instanceof ITestCase) {
                description = ((ITestCase) instance).getDescription(result);
            } else {
                Field f = result.getClass().getDeclaredField("m_description");
                f.setAccessible(true);
                description = (Description) f.get(result);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }
        return description;
    }

    /**
     * 獲取調用的所有註解
     * @param description
     * @return
     */
    private List getDeclaredAnnotations(Description description) {
        List classAnnotations = Lists.newArrayList();
        Class clazz = description.getTestClass();
        if (clazz != null) {
            classAnnotations.addAll(Arrays.asList(clazz.getDeclaredAnnotations()));
            classAnnotations.addAll(getDeclaredAnnotations(Description.createSuiteDescription(clazz)));
        }
        return ImmutableList.copyOf(Iterables.concat(
                Arrays.asList(description.getAnnotations()),
                classAnnotations));
    }

//運行測試用例:在@Test方法或@Test Class上加入@CategoryAnnotation注釋即可。
@CategoryAnnotation(value = { Category.LOGIN, Category.CHECKOUT }, component = {"UI"})
@Test
public void checkDefaultLoginRun() {
......
}

五、Conclusion

Allure Report是一個非常棒的測試報告工具,由於其美觀易讀、易於擴展、歷史報告以及趨勢分析等特點,在軟體測試中使用較為廣泛。希望大家能夠了解Allure Report,掌握使用方法,提高測試效率和進一步提升產品質量。

原創文章,作者:小藍,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/188556.html

(0)
打賞 微信掃一掃 微信掃一掃 支付寶掃一掃 支付寶掃一掃
小藍的頭像小藍
上一篇 2024-11-28 13:31
下一篇 2024-11-28 13:31

相關推薦

  • Python應用程序的全面指南

    Python是一種功能強大而簡單易學的編程語言,適用於多種應用場景。本篇文章將從多個方面介紹Python如何應用於開發應用程序。 一、Web應用程序 目前,基於Python的Web…

    編程 2025-04-29
  • Python zscore函數全面解析

    本文將介紹什麼是zscore函數,它在數據分析中的作用以及如何使用Python實現zscore函數,為讀者提供全面的指導。 一、zscore函數的概念 zscore函數是一種用於標…

    編程 2025-04-29
  • 全面解讀數據屬性r/w

    數據屬性r/w是指數據屬性的可讀/可寫性,它在程序設計中扮演著非常重要的角色。下面我們從多個方面對數據屬性r/w進行詳細的闡述。 一、r/w的概念 數據屬性r/w即指數據屬性的可讀…

    編程 2025-04-29
  • Python計算機程序代碼全面介紹

    本文將從多個方面對Python計算機程序代碼進行詳細介紹,包括基礎語法、數據類型、控制語句、函數、模塊及面向對象編程等。 一、基礎語法 Python是一種解釋型、面向對象、動態數據…

    編程 2025-04-29
  • Matlab二值圖像全面解析

    本文將全面介紹Matlab二值圖像的相關知識,包括二值圖像的基本原理、如何對二值圖像進行處理、如何從二值圖像中提取信息等等。通過本文的學習,你將能夠掌握Matlab二值圖像的基本操…

    編程 2025-04-28
  • 瘋狂Python講義的全面掌握與實踐

    本文將從多個方面對瘋狂Python講義進行詳細的闡述,幫助讀者全面了解Python編程,掌握瘋狂Python講義的實現方法。 一、Python基礎語法 Python基礎語法是學習P…

    編程 2025-04-28
  • 全面解析Python中的Variable

    Variable是Python中常見的一個概念,是我們在編程中經常用到的一個變數類型。Python是一門強類型語言,即每個變數都有一個對應的類型,不能無限制地進行類型間轉換。在本篇…

    編程 2025-04-28
  • Zookeeper ACL 用戶 anyone 全面解析

    本文將從以下幾個方面對Zookeeper ACL中的用戶anyone進行全面的解析,並為讀者提供相關的示例代碼。 一、anyone 的作用是什麼? 在Zookeeper中,anyo…

    編程 2025-04-28
  • Python合集符號全面解析

    Python是一門非常流行的編程語言,在其語法中有一些特殊的符號被稱作合集符號,這些符號在Python中起到非常重要的作用。本文將從多個方面對Python合集符號進行詳細闡述,幫助…

    編程 2025-04-28
  • Switchlight的全面解析

    Switchlight是一個高效的輕量級Web框架,為開發者提供了簡單易用的API和豐富的工具,可以快速構建Web應用程序。在本文中,我們將從多個方面闡述Switchlight的特…

    編程 2025-04-28

發表回復

登錄後才能評論