Jenkins集成Maven,Git自动化测试工程生成测试报告Allure Report

Selenium自动化测试,使用Jenkins自动化集成Maven工程, 想要生成直观简洁的测试报告可以使用Allure插件。

Allure介绍

Allure是一款非常轻量级并且非常灵活的开源测试报告生成框架。它简单易用,易于集成,并且支持绝大多数测试框架, 例如TestNG、Pytest、JUint等。

本文主要结合Jenkins与Maven、Allure集成做详细介绍。

环境准备

1、安装Jenkins

Jenkins 是基于Java开发的一种持续集成工具,所以首先必须搭建好Java环境(自行百度)。然后配置好Tomcat。
a、在https://jenkins.io/上下载Jenkins,把下载的jenkins.war放在tomcat的webapps的目录下,进入到tomcat的bin目录下,双击startup.bat文件启动tomcat。启动后,在浏览器中访问Tomcat配置监听的IP端口,默认访问地址:http://localhost:8080/jenkins

b、首次使用Jenkins需要输入密码,Windows下Jenkins登录密码在C:\Program Files (x86)\Jenkins\secrets目录下的initialAdminPassword文件中,复制其中的内容,把它copy到jenkins的密码输入框,点击下一步,配置账户密码,选择安装推荐插件或者手动选择都可以


image.png

c、全局工具配置
进入系统管理--全局工具配置,配置JDK、git、Maven


image.png

image.png
2、Allure 插件安装配置

a、进入Jenkins 系统管理---插件管理,在右侧的搜索框中直接搜索 allure,就可以看到 Allure Jenkins Plugin插件,点击安装。安装成功后,在已安装列表里查看到该插件的信息。


image.png

b、进入Jenkins 系统管理---全局工具设置,在全局工具设置的界面安装Allure,选择下载的插件版本,点击save保存。


image.png

自动化脚本准备

1、创建Maven工程

具体的内部代码实现,这里不再赘述。
a、配置pom.xml文件,添加Allure所需依赖包及插件

  <dependency>
            <groupId>io.qameta.allure</groupId>
            <artifactId>allure-java-commons</artifactId>
            <version>2.10.0</version>
            <scope>compile</scope>
        </dependency>

  <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-surefire-plugin</artifactId>
                <version>2.20</version>
                <configuration>
                    <suiteXmlFiles>
                        <suiteXmlFile>APD-DemoCase-Automation.xml</suiteXmlFile>
                    </suiteXmlFiles>
                    <argLine>
                        -javaagent:"${settings.localRepository}/org/aspectj/aspectjweaver/${aspectj.version}/aspectjweaver-${aspectj.version}.jar" -Dfile.encoding=UTF-8
                    </argLine>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>org.aspectj</groupId>
                        <artifactId>aspectjweaver</artifactId>
                        <version>${aspectj.version}</version>
                    </dependency>
                </dependencies>
            </plugin>

b、想要在打开的Allure测试报告里显示失败用例的截图和测试步骤,需要添加监听类
创建FailedStepListener类
使用Allure的@Attachment注解就可以在测试报告里显示附件。
这里首先获取执行的case的类的名称,然后与时间字符串拼接图片的名称以及图片的存储目录。如果目录不存在就自动创建。通过FileOutputStream流对象写入文件。

import io.qameta.allure.Attachment;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.testng.ITestResult;
import org.testng.TestListenerAdapter;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;

import static com.cccis.util.GlobalSetting.SCREENSHOT_PATH;

public class FailedStepListener extends TestListenerAdapter {
    @Override
    public void onTestFailure(ITestResult result){
        takeScreenshot(result);

    }

    @Attachment(value = "screenshot",type = "image/png")
    public byte[] takeScreenshot(ITestResult result){
        byte[] screenshotAs = ((TakesScreenshot)CommonTest.chrome_driver).getScreenshotAs(OutputType.BYTES);
        String[] classNameArr = result.getTestClass().getName().split("\\.");
        String className = classNameArr[classNameArr.length-1];
        String methodName = result.getName();
        String time  = new SimpleDateFormat("_yyyyMMdd_HHmmss").format(new Date());
        String date  = new SimpleDateFormat("yyyyMMdd").format(new Date());

        String scrFolder = SCREENSHOT_PATH+date+"/"+className;

        File dir = new File(scrFolder);

        if(!dir.exists()){
            dir.mkdirs();
        }

        String picPath = scrFolder+"/"+methodName+time+".png";

        try (FileOutputStream out = new FileOutputStream(picPath)){
            out.write(screenshotAs);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

        return screenshotAs;
    }
}

代码((TakesScreenshot)CommonTest.chrome_driver).getScreenshotAs(OutputType.BYTES)里的chrome_driver通过CommonTest类传过来。

import org.apache.logging.log4j.Logger;
import org.openqa.selenium.WebDriver;
import org.testng.Assert;
import org.testng.ITestContext;
import org.testng.annotations.AfterClass;
import org.testng.annotations.BeforeClass;

public class CommonTest {
    protected TestEnvSetup tes;
    public static WebDriver chrome_driver;
    protected Logger log;
    protected String testcaseName;
    protected SeleniumUtil seleUtilChrome;
    protected ITestContext testContext = null;

    @BeforeClass(alwaysRun = true)
    public void setup(ITestContext testContext) {
        testcaseName = this.getClass().getName();
        tes = new TestEnvSetup(testcaseName);
        log = tes.getLogger();
        chrome_driver = tes.iniChromeDriver();
        this.testContext = testContext;
        seleUtilChrome = new SeleniumUtil(chrome_driver, log);
        seleUtilChrome.keepOneWindow();
        testContext.setAttribute("driver", chrome_driver);
    }


    @AfterClass(alwaysRun = true)
    public void tearDown() {
        if (chrome_driver != null) {
            chrome_driver.close();
            chrome_driver.quit();
        } else {
            Assert.fail("driver没有获得对象,退出操作失败");
        }
    }
}

基础类TestEnvSetup

package com.cccis.util;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.testng.ITestContext;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import static com.cccis.util.GlobalSetting.*;

public class TestEnvSetup {
    WebDriver ieDriver;
    WebDriver chromeDriver;
    WebDriver driver;
    Logger log;
    ITestContext testContext;

    public TestEnvSetup(String testcaseName) {
        log = LogManager.getLogger(testcaseName);
    }

    public WebDriver iniChromeDriver() {
        ChromeOptions options = new ChromeOptions();
//        // 通过配置参数禁止data;的出现
//        options.addArguments("--user-data-dir=C:/Users/ccc/AppData/Local/Google/Chrome/User Data/Default");

        Map<String, Object> setting = new HashMap<>();
        setting.put("audiblePlaybacks", 0);
        setting.put("hasHighScore", false);
        setting.put("lastMediaPlaybackTime", 0.0);
        setting.put("mediaPlaybacks", 0);
        setting.put("significantPlaybacks", 0);
        setting.put("visits", 1);
        setting.put("visitsWithMediaTag", 0);

        Map<String, Object> ip = new HashMap<>();
        ip.put("last_modified", "13169187114098237");
        ip.put("setting", setting);

        Map<String, Object> media = new HashMap<>();
        media.put("http://19*.168.200.**:****,*", ip);

        Map<String, Object> exceptions = new HashMap<>();
        exceptions.put("media_engagement", media);
        Map<String, Object> plugins = new HashMap<>();
        Map<String, Object> ip2 = new HashMap<>();
        ip2.put("last_modified", "13169187019441329");
        ip2.put("setting", 1);
        plugins.put("http://19*.168.200.**:****,*", ip2);
        exceptions.put("plugins", plugins);

        Map<String, Object> contentSettings = new HashMap<>();
        contentSettings.put("exceptions", exceptions);
        Map<String, Object> profile = new HashMap<>();
        profile.put("avatar_bubble_tutorial_shown", 2);
        profile.put("avatar_index", 17);
        profile.put("content_settings", contentSettings);

        Map<String, Object> prefs = new HashMap<>();
        prefs.put("profile", profile);

// chrome68 不需要设置
// options.setExperimentalOption("prefs", prefs);
// 通过配置参数删除稳定性和安全性会有所下降提示
        options.addArguments("--start-maximized", "allow-running-insecure-content", "--test-type");
        options.addArguments("disable-infobars");
        System.setProperty("webdriver.chrome.driver", CHROME_DRIVER_PATH);

        chromeDriver = new ChromeDriver(options);
        // chromeDriver.manage().window().maximize();
        chromeDriver.manage().timeouts().implicitlyWait(ELEMENT_TIMEOUT, TimeUnit.SECONDS);
        SeleniumUtil.log(log,"启动测试浏览器为:[ Chrome ]");
        return chromeDriver;
    }

    public Logger getLogger() {
        return log;
    }
}

testng.xml中添加监听

<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="APD Demo UI Automation Testing" verbose="1" thread-count="1">
    <test name="All Testcase" preserve-order="true">
        <packages>
            <package name="com.***.testcase.*"/>
        </packages>
    </test> 

    <listeners>
        <!--<listener class-name="org.uncommons.reportng.HTMLReporter" />-->
        <listener class-name="com.cccis.util.FailedStepListener"/>
    </listeners>
</suite> 

最后测试用例对应类继承CommonTest类即可
c、如果Allure report需要自动生成在指定目录(默认生成于项目的根路径下),需要在项目的resources目录下创建allure.properties文件,文件的内容:

allure.results.directory=target/allure-results
2、将上述工程上传至git(如何上传自行百度)

构建Jenkins任务

1、构建一个maven项目

a、新建一个构建任务,选择 构建一个maven项目,取名如AllureDemo,点击确定


image.png

构建项目的时候,Jenkins会根据项目名称在工作空间里面创建一个目录(目录名称同项目名称)
例如,Jenkins在自己本地时,目录路径:C:\Users\用户名.jenkins\jobs\AllureDemo。 Jenkins会自动编译里面的源码。

b、在配置界面,进行以下配置


image.png

image.png

image.png

image.png

c、点击保存会返回项目详情页面,可以看到显示allure测试报告的图标


image.png

d、点击左侧立即构建,完成后可以看到构建的信息,点击allure测试报告即可以看到allure测试报告


image.png

这里遇到一个坑,点击图中的小图标,打开Allure报告显示404。
原因:Jenkins系统管理--系统设置中,Jenkins Location的Jenkins URL设置不正确,修改正确即可。

2、查看Allure Report 测试报告

Allure Report 测试报告主要分为总览、类别、测试套、图表、时间刻度、功能、包。
总览 ,中展示了本次测试的测试用例数量,成功用例、失败用例、跳过用例的比例,测试环境信息,SUITES,FEATURES BY STORIES等基本信息,当与Jenkins做了持续置成后,TREND区域还将显示,历次测试的通过情况。


image.png

Suites 按脚本的目录结果展示本次所有的测试用例执行情况


image.png

Behaviors功能
image.png

Categories类别
image.png

Graphs图表


image.png
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容