idea+java+testng+selenium+reportng搭建及测试

下一篇 appium 框架搭建
下一篇 基于 selenium 的 webui 框架终极版(有源码)

一.简介

写在前面:这一版本是本人搭建学习使用,后来改进了一个完全成熟版,同样也发布于 github 上了,博主强烈建议使用新版本拥有更好的体验

  • 使用工具介绍:
    idea 工具,行业中非常火的 java 开发工具;java 语言和 python 语言行业中常见的两种自动化测试需要的语言,我个人感觉可能java要用的多些;testng 是是testing的下一代测试技术,是一套根据 juint 和 nunit 思想构建的利用注释来强化测试功能的一个测试框架,既可以用来做单元测试,也可以用来做集成测试,实际上用 junit + selenium 也未尝不可,但没有 testng 来的强大。selenium 是基于 web 自动化的开源框架,提供众多方法,来完成浏览器页面的一些复杂操作,支持所有主流浏览器,支持众多脚本语言(java,python,ruby,php,c#等),支持所有主流操作系统。reportng 来取代优化 testng 原有的测试报告,原有测试报告效果较难直观显示测试结果,reportng 工具开源,也可以自己做优化报告的拓展,对前端技术要求高点。
  • 项目介绍
    selenium 测试做的是 UI 测试,控制模拟浏览器点击等操作,来模拟用户再浏览器中的点击。selenium 中提供了 WebDriver 类,此类提供多种控制浏览器的方法。testng 提供多种注解,类似junit一些注解,通过 testng.xml 文件的形式来管控各个测试用例的运行并发等。实际项目上常将其部署在服务器中的 jenkins 中来定时定量跑测试用例。而 jenkins 也是目前行业中最主流的基于 java 开发的持续集成工具。本人在搭建 selenium 这个项目过程中,原理主要是通过每个测试用例类继承一个基类,每个测试用例类中有个被 @Test 注解标记的测试方法,在 @Test 执行之前会首先执行基类中某个方法,来设置浏览器驱动并开启浏览器的过程,项目中通过 xml 文件管理所有测试用例,里头可以进行多线程等管控。

二.项目结构

  • 下面是我搭建的 selenium 的项目结构:
	- .idea
	- src
	  - main
	    - java(里头有测试基类和各个测试用例)
	    - resource
	      - drivers
	      - config.properties
	      - log4j.properties
	      - README.md
	      - testNg.xml
	  - test
	    - java
	- test-output
	    - html
	    - screenshots
	    - xml
	- pom.xml
	- README.md
	- seleniumTest.iml

三.引入依赖

本人引入了众多依赖包,主要分为5大类:

  • 其他依赖包: guava;junit;
  • testNg 依赖: testng;
  • reportNg 依赖: reportng;
  • selenium 相关依赖: selenium-java; selenium-server;selenium-htmlunit-driver;selenium-iphone-driver;selenium-android-driver;
  • log4j 依赖: slf4j-api;slf4j-log4j12;
    注意 :我之所以在开头引入了 guava,是因为这个包在其他依赖中的此包因为版本原因冲突了,我就干脆把这个包单独引入并且放在依赖开头来防止冲突。

四.搭建步骤

下面为本人从头到尾的搭建步骤 9 步:

  1. 创建项目,引入依赖
    在 idea 中创建 maven 项目,引入上面所需要的依赖
  2. 在 pom 文件中进行插件的配置
    主要就是 reportng 的配置,配置不使用默认testng的报告,而使用 reportng 报告,之后还需要在 testng.xml 中添加监听,pom 中的 plugin 代码如下:
    <!-- 添加插件,添加ReportNg的监听器,修改最后的TestNg的报告 -->
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-surefire-plugin</artifactId>
        <version>2.20.1</version>
        <!-- 配置testNg.xml 控制测试范围和特性与产出报告 -->
        <configuration>
            <!-- testNg 执行出错仍然继续执行 -->
            <testFailureIgnore>true</testFailureIgnore>
            <!-- testNg 相关的 xml 配置文件 -->
            <suiteXmlFiles>
                <!-- 指定使用的 testNg.xml 位置 -->
                <suiteXmlFile>${xmlFileName}</suiteXmlFile>
            </suiteXmlFiles>
            <!-- 添加 reportNg 监听器,来修改 testNg 的报告 -->
            <properties>
                <!-- 线程池多线程,在xml中配置 -->
                <property>
                    <name>suitethreadpoolsize</name>
                    <value>2</value>
                </property>
                <!-- 是否使用默认监听器,在testNg.xml中配置 -->
                <property>
                    <name>usedefaultlisteners</name>
                    <value>false</value> <!-- 由于要使用reportNg生成的报告,置为false,此时要在 testNg.xml 配置监听器 -->
                </property>
                <!-- listener -->
                <property>
                    <name>listener</name>
                    <value>org.uncommons.reportng.HTMLReporter, org.uncommons.reportng.JUnitXMLReporter</value>
                </property>
            </properties>
            <!-- 编码设置,否则生成报告乱码 -->
            <argLine>-Dfile.encoding=UTF-8</argLine>
        </configuration>
    </plugin>
    
  3. 开始准备 testng.xml 文件,并将其放置于 resource 资源文件夹下
    testng.xml 主要分为两大部分,配置监听部分和测试用例部分,如下:
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
    <suite name="My suite" parallel="tests" thread-count="4">
    	<!--listener 不使用默认产生报告的监听器配置,自己写明一个产生报告的监听器-->
        <listeners>
            <listener class-name="org.uncommons.reportng.HTMLReporter" />
            <listener class-name="org.uncommons.reportng.JUnitXMLReporter" />
        </listeners>
        <test verbose="2" name="MyTest">
            <parameter name="propertiesPath" value="src/main/resources/config.properties" />
            <parameter name="browserType" value="chrome" />
            <parameter name="browserVersion" value="xxx" />
            <!-- 指定 case 路径 -->
            <!--<parameter name="remoteIP" value="xxx" />-->
            <classes>
                <class name="com.example.mytest.MyTest2" />
            </classes>
        </test>
    </suite>
    
  4. 配置 log 输出报告
    为了让 log 显示自己需要的形式,并且可以输出 logs 报告,在 resource 路径下配置 log4j.properties,properties 的文件内容可参见网络,之后默认输出的就是与 src 同级的 logs 目录。此 properties 的具体写法可参见 log4j.properties 的写法
  5. 浏览器驱动的下载
    下载市场上主流的浏览器的驱动,注意是 64bit 还是 32bit,是什么操作系统的驱动,放置于 resource/drivers 路径下
  6. 添加与驱动等环境有关的 properties 文件
    此文件主要存放系统和驱动的变量,之后在测试类基类中读取此文件中的各个参数,之所以弄成 properties 文件的形式,是为了便于直接在 properties 中对参数进行修改,而不会存在以后对代码直接进行修改的情况。properties 文件中参数主要有浏览器类型,驱动在项目中的路径,驱动初始化后第一个要开启的网址
  7. 测试类基类编写
    测试类基类是供其他测试类继承使用的,其中有 @BeforeTest 注解标注的方法,主要是初始化驱动参数,开启浏览器的,而这些参数可以从第 6 步骤的 properties 的配置文件中取到,基类的具体代码下面会有写。
  8. 几个简单的测试用例
    测试用例继承测试基类,在测试用例中的方法上表名 @Test 注解,将测试用例逐一配置于 testng.xml 中,如 3 步,之后不论是去跑单个用例还是直接去跑 testng.xml 都是可以的。在 Run → Edit Configurations 中可以配置报告的输出路径

以上过程算是完成了整个环境基本测试功能的搭建,下面有一些很有用的附加功能

  1. 截图功能的实现
    做法:在测试类上标明 @Listeners 注解,注解括号中包括一个需要被监听的类,这个类需要继承 TestListenerAdapter 这个监听的类,之后再配置一下 testng.xml 的截图监听,这样就可以一报错,就 new 一个被监听的类的对象,执行其中的截图方法。本人是将这个被监听的类弄成和测试基类是同一个类,也就是说这个测试基类是继承 TestListenerAdapter 这个监听的类,这个测试基类中写有截图的方法,这个截图的方法需要重写 onTestFailure() 这个方法才行。

五.基类中的重点代码

  • 设置驱动:
    // this.chromeDriverPathP 为驱动的相对于项目中的路径
    File file = new File(this.chromeDriverPathP);
    // 设置 System 参数,其中 TestConstants.CHROME_DRIVER_NAME 为驱动名,file.getAbsolutePath()为驱动的绝对路径
    System.setProperty(TestConstants.CHROME_DRIVER_NAME, file.getAbsolutePath());
    this.driver = new ChromeDriver();
    
  • 窗口最大化并打开网页:
    // 窗口最大化
    driver.manage().window().maximize();
    // 打开网页,其中urlP是要打开的网址,要写全
    driver.get(urlP);
    
  • 隐式等待:
    // 隐式等待是在该驱动的生存区间内有效
    driver.manage().timeouts().implicitlyWait(10, TimeUnit.SECONDS);
    
  • 退出测试
    // 与@BeforeTest注解类似,退出测试的方法上加上@AfterTest注解
    // 利用JS弹出弹框显示测试结束
    this.javascriptExecutor.executeScript(TestConstants.FINISH_ALERT);
    // 驱动退出
    this.driver.quit();
    String command = "taskkill /F /IM";
    command = command + "chromedriver.exe"; 
    try {
    	// 运行关闭浏览器进程的命令
        Runtime.getRuntime().exec(command);
    } catch (IOException e) {
    	e.printStackTrace();
    }
    
  • 截图功能:
    需要继承的监听类是:TestListenerAdapter,需要重写的方法如下:
    @Override
    public synchronized void onTestFailure(ITestResult result){
    }
    
    由于每次监听到异常抛出时,会调用继承自监听类中被重写的上面这个方法,但是每次是会 new 一个监听类的对象,这样相应测试用例的 driver 就没有取到,可以用下面这种方式来取到对应测试用例的 driver:
    // 先获取当前 Object 类型的测试类
    Object currentClass = result.getInstance();
    // 获取当前测试类驱动
    WebDriver currentDriver = ( (测试基类) (currentClass) ).driver;
    
    具体截图功能实现:
    File srcFile= ((TakesScreenshot)currentDriver).getScreenshotAs(OutputType.FILE);
    // 其中result是重写方法中的参数,formatDate是String类型的当前日期
    // 存放截图路径,名字中有日期
    String picPath = "test-output/screenshots/" + result.getTestClass().getRealClass().getSimpleName() + formatDate + ".png";
    
    截图附在reportng报告中:
    // 在 report 报告中输出截图
    Reporter.log("<a href=\"../../" + picPath + "\" target=_blank>Failed Screen Shot</a>", true);
    

六.搭建过程中遇到的问题和需要注意的问题

  • 引入依赖问题
    引入依赖可能会有冲突问题,本人一开始引入依赖发现冲突,后来发现是 guava 包的依赖发生冲突,因为有的依赖包中是包含 guava ,但是写在前面的依赖会成为默认依赖,后面的依赖中即使有此 guava 依赖也会被忽略掉,所以当后面的依赖包中含有或者说需要使用不同版本的 guava 包时候就会发生冲突。所以查看冲突原因后直接将某一版本的 guava 包提在 pom 最开头。idea 中有右侧边栏可以查看 maven 项目的依赖视图,或者使用 mvn dependency:tree -Dverbose 来查看依赖树也是可行的
  • 初始化驱动后打开网站问题
    driver 的 get() 方法打开网站需要是完整的包含 http 协议的地址
  • 文件名称问题
    文件名称不能包含/或\或:等字符
  • testng.xml 文件
    此文件中可以设置多线程,设置运行具体的哪些测试用例,可以按组划分,按各种类型划分

七.项目还可以优化的问题

  • 1.与jenkins建立继承在服务器端跑的问题
  • 2.驱动版本需要下载对,对应系统的主流驱动需要下载全,注意 64 位还是 32 位
  • 3.report 文档可以自己去优化或者网上有许多已经优化过的或者再次优化 reportng 的教程