自动化测试--实现一套完全解耦的简单测试框架(二)

一:每次运行都需要打开代码工具,如eclipse或者IDE等。为了后面的持续集成,直接使用Maven命令去运行自动化测试,需要引入surfire插件。笔者使用的是2.10版本Surefire和6.9.10版本TESTNG。

 下面是项目完整的pom文件:

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0modelVersion>
    <groupId>com.claire.leaflygroupId>
    <artifactId>projectLemonartifactId>
    <version>0.0.1-SNAPSHOTversion>
    <dependencies>

        <dependency>
            <groupId>org.seleniumhq.seleniumgroupId>
            <artifactId>selenium-javaartifactId>
            <version>3.4.0version>
        dependency>

        
        <dependency>
            <groupId>org.testnggroupId>
            <artifactId>testngartifactId>
            <version>6.9.10version>
            <scope>testscope>
        dependency>

        
        <dependency>
            <groupId>dom4jgroupId>
            <artifactId>dom4jartifactId>
            <version>1.6.1version>
        dependency>


        
        <dependency>
            <groupId>log4jgroupId>
            <artifactId>log4jartifactId>
            <version>1.2.17version>
        dependency>

        
        <dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poi-ooxmlartifactId>
            <version>3.17version>
        dependency>


        <dependency>
            <groupId>xml-apisgroupId>
            <artifactId>xml-apisartifactId>
            <version>1.4.01version>
        dependency>

        
        <dependency>
            <groupId>org.uncommonsgroupId>
            <artifactId>reportngartifactId>
            <version>1.1.4version>
            <scope>testscope>
        dependency>

        
        <dependency>
            <groupId>com.google.injectgroupId>
            <artifactId>guiceartifactId>
            <version>3.0version>
        dependency>


        
        <dependency>
            <groupId>org.mybatisgroupId>
            <artifactId>mybatisartifactId>
            <version>3.4.1version>
        dependency>

        
<dependency>
    <groupId>mysqlgroupId>
    <artifactId>mysql-connector-javaartifactId>
    <version>8.0.11version>
dependency>




    dependencies>
    <build>
        <plugins>
            
            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-compiler-pluginartifactId>
                <version>3.5.1version>
                <configuration>
                    <source>1.8source>
                    <target>1.8target>
                    <encoding>UTF-8encoding>
                configuration>
            plugin>

            <plugin>
                <groupId>org.apache.maven.pluginsgroupId>
                <artifactId>maven-surefire-pluginartifactId>
                <version>2.10version>
                <configuration>
                    <systemPropertyVariables>
                        <org.uncommons.reportng.escape-output>falseorg.uncommons.reportng.escape-output>//是否忽略html,解释见下图。与之后在reportNg报告上显示截图相关。
                    systemPropertyVariables>
                    <testFailureIgnore>truetestFailureIgnore>//测试失败后,是否忽略并继续测试
                    <argLine>
                        -Dfile.encoding=UTF-8
                    argLine>

                    <suiteXmlFiles>
                        <suiteXmlFile>register.xmlsuiteXmlFile>//代表的是要执行的测试套件名称
                    suiteXmlFiles>

                configuration>
            plugin>

        plugins>
    build>

project>

自动化测试--实现一套完全解耦的简单测试框架(二)_第1张图片

该配置与reportng相关,后面有详细的解释和源码。

 

 在pom中设置好surefire插件之后,即可使用maven test来执行设置好的测试套件。

注意点(坑):

1.读者使用的各插件或者jar包版本与笔者不同,在执行maventest时,如果未能执行测试套件。请尝试选择不同的suifire插件版本。

2.如上配置的register.xml---------------------register.xml该文件一般都放置在根目录下,否则有时会报错

 

 

二、在测试完成之后,通常希望得到一份完善的测试报告。TESTNG的测试报告,太过简陋,笔者引入reportNG的jar包

1.引入reportng依赖

2.在register.xml中,添加监听器NewHtmlReporter,用于渲染reportng 生成的测试报告。

xml version="1.0" encoding="UTF-8"?>
DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="suitName_register" parallel="false">

    <test name="testName_register">

        <classes>

            
            <class name="com.demo.auto.claire.testcase.register.Register_SuccessTester_002" />

        classes>
    test> 
    <listeners>
    
    <listener class-name="org.uncommons.reportng.HTMLReporter" />//先添加该监听器,后面添加自定义监听器NewHtmlReporter后,该监听器就可以删掉了
  




<listener class-name="com.demo.auto.claire.listener.ListenerFailTestScreenShot">
listener>

listeners>

suite>

 

 

注意(坑):

对项目右键--run as --maven test时,如果报Injector类找不到时,需要引入guice依赖。(也可以升级testng的版本,查找到依赖了guice jar的相应版本即可)

 

三:此时使用reportng生成了测试报告,比testng的要美观一些。但是我们希望可以对其进行定制

1.显示出每一列的名称

2.显示错误的截图.效果如下:自动化测试--实现一套完全解耦的简单测试框架(二)_第2张图片

 

 

1.在测试完成之后,需要对失败的用例进行截图。自定义监听器,在测试失败的时候,进行截图。

 

看一下关于监听的继承和实现关系图

自动化测试--实现一套完全解耦的简单测试框架(二)_第3张图片

 

 可以看到,ITestListener接口中定义了方法onTestFailure,自定义监听类可以实现改接口,重写该方法。但是,此时需要重写改接口所有的方法。即使方法体里面为空,代码也不会美观。最后笔者选择将自定义监听器继承类TestListenerAdapter,只重写该类中的onTestFailure方法即可。下面是代码示例:

 

 1 package com.demo.auto.claire.listener;
 2 
 3 import java.io.File;
 4 import java.io.IOException;
 5 import java.text.SimpleDateFormat;
 6 import java.util.Calendar;
 7 
 8 import org.apache.bcel.generic.SIPUSH;
 9 import org.testng.ITestResult;
10 import org.testng.Reporter;
11 import org.testng.TestListenerAdapter;
12 
13 import com.demo.auto.claire.base.BaseTester;
14 import com.demo.auto.claire.util.ScreenShotUtil;
15 
16 public class ListenerFailTestScreenShot extends TestListenerAdapter {
17 
18     @Override
19     public void onTestFailure(ITestResult tr) {
20         
21         // 获取到当前的年月日
22         SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd");
23         Calendar calendar = Calendar.getInstance();
24         //calendar.getTime()得到的时间是这样的:Fri Aug 31 16:16:51 CST 2018,需要格式化成年月日
25         String time = dateFormat.format(calendar.getTime());
26         //也可以直接使用 
27         //String time2 =  dateFormat.format(new java.util.Date()
28         
29         //获得几点周几
30         //SimpleDateFormat dateFormat2 = new SimpleDateFormat("EEEE");
31         //String week = dateFormat2.format(new java.util.Date());
32         
33         // D:\myTest\projectLemon\target\surefire-reports\registertest_register_success_002\2018-08-31
34         
35                 String outPutDirectory=tr.getTestContext().getOutputDirectory();
36                 //获取到测试的方法名称
37                 String methodName= tr.getName();
38                 
39                 String path1 = outPutDirectory +File.separator+methodName +File.separator+time;
40                 /*System.out.println("##################################");
41                 System.out.println(path1);
42                 System.out.println(outPutDirectory);
43                 System.out.println(methodName);*/
44                 
45                 String imgName=null;
46 
47         
48         try {
49             //当测试不通过的时候,调用截图的代码
50             imgName = ScreenShotUtil.screenShot(BaseTester.driver, path1);
51         } catch (IOException e) {
52 
53             e.printStackTrace();
54         }
55         
56         //Reporter.log("测试代码");
57         //http://localhost:7777/registertest_register_success_002/2018-09-01%E6%98%9F%E6%9C%9F%E5%85%AD/1535807491038.png
58         //String imgHerf2 ="/" +methodName+"/"+ time+"/"+imgName;
59         String suitName = tr.getTestContext().getCurrentXmlTest().getSuite().getName();
60         String imgHerf = "../" +String.join("/",suitName, methodName,time,imgName);
61         //下面这句代码是将截图添加到reportNg的报告中使用的,log的内容会显示在报告上
62         Reporter.log("查看大图");
63 //        System.out.println("******************************");
64 //        System.out.println(imgHerf);
65 
66         
67         super.onTestFailure(tr);
68     }
69 
70 }
View Code

该监听器监听到测试失败之后,会调用截图帮助类中的方法进行截图。代码示例:

package com.demo.auto.claire.util;

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

import org.apache.commons.io.FileUtils;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.WebDriver;
import org.testng.ITestResult;


public class ScreenShotUtil {
    public static void main(String[] args) {
        WebDriver driver = SeleniumUtil.getDriver();
        //driver.get("http://www.baidu.com");
    //    screenShot(driver);
        
    }
    
    public static String screenShot(WebDriver driver,String path) throws IOException {
        
        File srcFile = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE);
        
        //String path = sr.getTestContext().getOutputDirectory();
        
        //FileUtils.copyFileToDirectory(srcFile, new File(path));
        //冒号是路径非法字符,路径中不能出现冒号,所以时分秒选择了使用“-”
        String fileName = (new SimpleDateFormat("HHmmss")).format(new Date())+".png";
        String pathname = path+File.separator+ fileName ;
        
        System.out.println("pathname:"+pathname);
        FileUtils.copyFile(srcFile, new File(pathname));
        return fileName;
    }

}
View Code

如果是使用maventest执行的测试,则截图存储在target目录下面.(右键test-output,找到同级的target目录-----------surfire-reports ---------------- 套件名称----------- 测试名称 --------------年月日 --------时分秒.png)

 自动化测试--实现一套完全解耦的简单测试框架(二)_第4张图片

如果使用的是testng执行的测试,则截图保存在test-output--------------------surfire-reports ---------------- 套件名称----------- 测试名称 --------------年月日 --------时分秒.png

自动化测试--实现一套完全解耦的简单测试框架(二)_第5张图片

 

 

2.下面讲一下,如何定制reportng

a.修改其配置文件,增加列名

自动化测试--实现一套完全解耦的简单测试框架(二)_第6张图片

自动化测试--实现一套完全解耦的简单测试框架(二)_第7张图片

自动化测试--实现一套完全解耦的简单测试框架(二)_第8张图片

上图中的文本是:(可根据喜好,自行配置)-----修改完成之后,记得托回到jar包中去

log=Log Info
screenshot=Screen Shot
duration=Duration

 

自动化测试--实现一套完全解耦的简单测试框架(二)_第9张图片

 

 打开并修改上述文件:

自动化测试--实现一套完全解耦的简单测试框架(二)_第10张图片

 

 上图中的文本是:-----修改完成之后,记得托回到jar包中去

#if ($failedTests.size() > 0)
  <table class="resultsTable">
    <tr><th colspan="4" class="header failed">$messages.getString("failedTests")th>tr>
    #foreach ($testClass in $failedTests.keySet())
      <tr>
        <td colspan="1" class="group">$testClass.nametd>
        <td colspan="1" class="group">$messages.getString("duration")td>
        <td colspan="1" class="group">$messages.getString("log")td>
        <td colspan="1" class="group">$messages.getString("screenshot")td>
      tr>
      #set ($classResults = $failedTests.get($testClass))
      #parse ("org/uncommons/reportng/templates/html/class-results.html.vm")
    #end
  table>
#end

 

 上面两步,完成了给测试失败的用例,添加3个列名。

 

接下来修改源码和模板文件,将截图添加进入。

在上述的测试失败进行截图的监听器中,有一句代码是这样的

自动化测试--实现一套完全解耦的简单测试框架(二)_第11张图片

 

 reporter.log("XXX")-------这个xxx的内容就会显示在我们的Log info列。---------------下一步,就是要将图片从log info列删除,在screen shot列添加:

 

自动化测试--实现一套完全解耦的简单测试框架(二)_第12张图片

打开该指定文件。

自动化测试--实现一套完全解耦的简单测试框架(二)_第13张图片

 

 上图文本为:

   ## Show logger output for the test.
    #set ($output = $utils.getTestOutput($testResult))
    #if ($output.size() > 0)
    <div class="testOutput">
      #foreach( $line in $output )
        #if ($meta.shouldEscapeOutput())
          $utils.escapeHTMLString($tools.removeImage($line))<br />
        #else
          $tools.removeImage($line)<br/>
        #end
      #end
    div>
    #end

自动化测试--实现一套完全解耦的简单测试框架(二)_第14张图片

上图文本为:

<td class="screenshot">
    ## Show logger output for the test.
    #set ($output = $utils.getTestOutput($testResult))
    #if ($output.size() > 0)
    <div class="screenshotimage">
      #foreach( $line in $output )
        #if ($meta.shouldEscapeOutput())
          $utils.escapeHTMLString($tools.getImageString($line))<br />
        #else
          $tools.getImageString($line)<br/>
        #end
      #end
    div>
    #end
  td>

可以看到,上面试使用tools.getImageString()  、tools.removeImage来获取和删除图片的。这个tools是哪里来的呢?

我们看到reportng自己的方法都是使用的 这个util的对象是从哪里注册进来的?

自动化测试--实现一套完全解耦的简单测试框架(二)_第15张图片

自动化测试--实现一套完全解耦的简单测试框架(二)_第16张图片

 

 

 可以看到HTMLreporter继承了AbstractReporter,AbstractReporter中定义了一个final的常量UTILS----引用指向的是ReportNGUtils对象,该ReportNGUtils定义了各种方法,供模板文件中调用。又通过creatContext的方式注册进模板文件(VelocityContext)对象中.

 

那么想要在模板文件中删除和加上图片,有2种方式,

第一:修改ReportNGUtils类,在其中加上删除和引入图片的方法。会涉及到修改源码,修改源码通常也有2种方式:

    1.下载源码,修改,完成后重新打jar包并引入------------操作起来比较麻烦

    2.在自己的项目下,生成一个与reportng一致的包名和类名(org.uncommons.reportng.HTMLReporter.class),在其中修改代码。----------这样的话,如果别人引入了你的jar包又引入了reportng的jar包,要考虑下到底使用的谁的。

第二:自定义一个NewHtmlReporter,去继承HTMLReporter,重写父类的creatContext方法,将自己的工具类引入。

下面是NewHtmlReporter 的源码

package com.demo.auto.claire.util;

import org.apache.bcel.generic.NEW;
import org.apache.velocity.VelocityContext;
import org.uncommons.reportng.HTMLReporter;


public class NewHtmlReporter extends HTMLReporter{
    
     private static final ReportNgTools TOOLS = new ReportNgTools();
             
             
    @Override
    protected VelocityContext createContext() {
        VelocityContext context = super.createContext();
        context.put("tools", TOOLS);
        return context;
        
    }

}

下面是自己实现了删除和增加截图的工具类ReportNgTools源码:

package com.demo.auto.claire.util;

import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ReportNgTools {
    public String sayHello() {
        return "love";         
    }
    
    
    public String removeImage(String log) {
        //正则表达式
        String regex = ".*";
        //匹配到正则的内容,将其用空字符替换
        return log.replaceAll(regex, "");
        
    }
    
    public String getImageString(String log) {
        //正则表达式
        String regex = ".*";
        //将正则表达式编译为Pattern对象
        Pattern pattern = Pattern.compile(regex);
        //通过正则表达式对象去匹配log内容
        Matcher matcher = pattern.matcher(log);
        
        //如果匹配到了,则返回第0组(第0组是包含了所有匹配到的数据)
        if (matcher.find()) {
            return matcher.group(0);
        }
        //否则返回空
        return "";
        
    }

}

 

 此时,我们直接引入自己的监听即可:

xml version="1.0" encoding="UTF-8"?>
DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >

<suite name="suitName_register" parallel="false">

    <test name="testName_register">

        <classes>

            
            <class name="com.demo.auto.claire.testcase.register.Register_SuccessTester_002" />

        classes>
    test> 
    <listeners>
    
    
    
    <listener class-name="com.demo.auto.claire.util.NewHtmlReporter" />
    
    <listener class-name="com.demo.auto.claire.listener.ListenerFailTestScreenShot">listener>
    listeners>
suite> 

 

综上就完成了关于reportng定制的部分

 

转载于:https://www.cnblogs.com/clairejing/p/9581704.html

你可能感兴趣的:(自动化测试--实现一套完全解耦的简单测试框架(二))