使用TestNG实现系统集成测试

Posted 乱七八糟谈技术

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用TestNG实现系统集成测试相关的知识,希望对你有一定的参考价值。

很多项目在开发初期忽略了自动化测试,原因不外乎以下几种:项目比较紧张,自动化测试投入比较大,影响项目的交付;自动化测试投入很大,效果初期不是很明显;团队开发人员对自动化测试不是很了解,在开发过程中需要制造很多假数据,开发很繁琐,因此主观上不愿意开发自动化测试代码。但随着项目越做越大,以及开发人员的变更,代码不断被重构和修改,会出现改一个很小的地方导致很多相关功能出现异常。
自动化测试(Automated Test),很多团队都在做,但是往往效果不明显。究其原因还是对自动化测试的理解误区, 以为有了自动化后,就不需要手工测试了,因此将一些不适合做自动化的测试用例进行自动化,导致了投入产出比过高。同时,由于缺乏好的统一的测试框架支持,自动化测试脚本编写的复杂度过高,维护性差,耗费了测试人员大量的精力来编写和维护自动化测试用例。因此,为了更好的发挥自动化测试的功效,不能为了自动化测试而做自动化测试,主要是从项目的功能角度,开发比较合理和核心的测试用例尤为重要。在 Java的世界有两个测试框架JUnit和TestNG,关于它们的比较有很多,可以参考https://www.jianshu.com/p/d1e4d4aa9aa5。在考虑所有功能比较之后,建议使用TestNG作为Java项目的核心单元测试框架,因为TestNG在参数化测试,依赖测试和套件测试(分组概念)方面更加突出。 TestNG用于高级测试和复杂集成测试。 它的灵活性对于大型测试套件尤其有用。 此外,TestNG还涵盖了整个核心的JUnit4功能。因此在项目中使用了TestNG作为测试框架,选TestNG更加重要的原因是因为TestNG的运行不依赖于Eclipse,可以独立运行,因此更适合用作集成测试。

安装TestNG

测试场景

在项目中需要实现的一个测试用例是,我们对设备某个参数进行控制,比如我们需要设置空调的温度为23度,通过平台下发控制命令,然后延时去读取下发的控制参数是否设置成功,读取设备返回的温度是否是23度。这是一个典型的集成用例。此外,我们需要持续测试这个功能,每小时测试一次来监控平台的稳定运行。下面将根据具体的例子详细介绍如何实现此测试用例,并使其独立运行。

开发测试用例
步骤一,熟悉TestNG基本语法

使用TestNG开发测试用例实际不复杂,主要使用annotation来标注每个方法,理解应该不复杂。

Annotation使用

public class TestngAnnotation {

       // Test Case 1
       @Test
       public void testCase1() 
{
          System.out.println("in Test Case 1");
       }

       // Test Case 2
       @Test
       public void testCase2() 
{
          System.out.println("in Test Case 2");
       }

       @BeforeMethod
       public void beforeMethod() 
{
          System.out.println("in Before Method");
       }

       @AfterMethod
       public void afterMethod() 
{
          System.out.println("in After Method");
       }

       @BeforeClass
       public void beforeClass() 
{
          System.out.println("in Before Class");
       }

       @AfterClass
       public void afterClass() 
{
          System.out.println("in After Class");
       }

       @BeforeTest
       public void beforeTest() 
{
          System.out.println("in Before Test");
       }

       @AfterTest
       public void afterTest() 
{
          System.out.println("in After Test");
       }

       @BeforeSuite
       public void beforeSuite() 
{
          System.out.println("in Before Suite");
       }

       @AfterSuite
       public void afterSuite() 
{
          System.out.println("in After Suite");
       }

}

输入的结果如下:

[TestNG] Running:

in Before Suite
in Before Test
in Before Class
in Before Method
in Test Case 1
in After Method
in Before Method
in Test Case 2
in After Method
in After Class
in After Test
in After Suite

===============================================
Default suite
Total tests run: 2, Failures: 0, Skips: 0
===============================================


Assert使用

下面是Assert支持的方法

使用TestNG实现系统集成测试

步骤二,使用DataProvider传入参数

在我的项目中,需要有很多的sample数据,比如上个用例中提到的具体设备参数,这些都可以统统DataProvider传入。以下是部分代码,从json文件中读取样例数据,传入到testPointValue方法。

protected Sample prepareData() {
        try {
            FileReader fr = new FileReader("src/main/resources/samples.json");
            Gson gson = new Gson();
            return gson.fromJson(fr, Sample.class);

        } catch (IOException e) {
            LOG.error(LogStackTrace.getStringFromException(e));
        }
        return null;
    }
@DataProvider(name="sampleData")
    public Object[][] getSampleData() {
        Sample sample = prepareData();
        Object[][] arr = null;
        if(sample != null){
            List<PointValueSample> pointValueSamples = sample.getPointvaluesamples();
            arr = new Object[][]{{pointValueSamples, null}};
        }
        return arr;
    }

@Test(dataProvider="sampleData")
    public void testPointValue(List<PointValueSample> pointValueSamples, Object unUsed){
}
步骤三,修改Report的位置

因为我们的需求需要每一个小时运行一次,因此需要把每次的report放置到一个独立的位置,不会被下次运行而覆盖,TestNG提供了修改report的方法。如下每次运行创建一个以当前时间为目录的文件夹,每次运行的Report将被放在此目录下。

@BeforeTest
    public void setup(ITestContext ctx) {
        TestRunner runner = (TestRunner) ctx;
        String date = getCurrentTime();

        File directory = new File(date);
        if (!directory.exists()) {
            directory.mkdir();
        }
        runner.setOutputDirectory(date);
    }
步骤四,开发测试用例

以上面提到的测试用例为例子,先设置参数值,延时读取参数值来验证是否设置成功,代码如下:

@Test(dataProvider="sampleData")
    public void testPointValue(List<PointValueSample> pointValueSamples, Object unUsed){
        try {
            Assert.assertTrue(pointValueSamples != null && !pointValueSamples.isEmpty());
            Reporter.log("start pointvalue integration test at " + getCurrentTime());

            Map<Integer, List<PointValueSample>> pointValueSampleMap = pointValueSamples.stream().collect(Collectors.groupingBy(PointValueSample::getSiteId));
            for(Map.Entry<Integer, List<PointValueSample>> item:pointValueSampleMap.entrySet()){
                List<Integer> points = item.getValue().stream().map(p->p.getPointId()).collect(Collectors.toList());
                Map<String, PointInformation> map = getPointInformation(item.getKey(), points);
                List<PointValue> pointValues = new ArrayList<PointValue>();
                if (map != null && !map.isEmpty()) {
                    for (Map.Entry<String,PointInformation> m : map.entrySet()) {
                        PointValue pointValue = generateRandomPointValue(Integer.parseInt(m.getKey()), m.getValue().getValueType());
                        pointValues.add(pointValue);
                    }
                }
                //set parameter
                boolean bRet = setPoint(item.getKey(), pointValues);
                Assert.assertTrue(bRet);

                //wait 1 minute
                Thread.sleep(20000);
                //get parameter value       
                Map<String, PointValue> responsePointValues = getPointValues(item.getKey(), points);
                Assert.assertNotNull(responsePointValues);
                for(Map.Entry<String, PointValue> entry:responsePointValues.entrySet()){
                    PointValue pv = pointValues.stream().filter(p->p.getId() == Integer.parseInt(entry.getKey())).findFirst().get();
                    Assert.assertNotNull(pv);
                    Assert.assertTrue(comparePointValue(pv, entry.getValue()));
                }               
            }
            Reporter.log("end pointvalue integration test at " + getCurrentTime());

        } catch (Exception e) {
            log.error(LogStackTrace.getStringFromException(e));
        }
    }
步骤五,生成TestNG的xml文件并运行

为了使TestNG独立运行,需要生成TestNG的配置文件,可以通过Eclipse来自动生成,方法如下:

  • 选择TestNG的类文件,右键,菜单中会有TestNG

  • 选中Convert to TestNG
    这样会生成一个testng.xml文件,也可以自己按照自己的测试用例修改这个xml文件。
    在Eclipse中也可以运行TestNG,方法如下:

  • 选择TestNG的类文件,右键Run as 选择TestNG

步骤六,输入所有的依赖包

为了使TestNG能独立运行,必须将所有的依赖包输出在一个目录下,目录结构可以按如下组织,使用Maven的maven-compiler-plugin实现将编译class输出到bin目录,使用Maven的maven-dependency-plugin实现将依赖的jar包输出到lib目录下,使用Maven的maven-assembly-plugin实现打包。

目录结构如下:

使用TestNG实现系统集成测试

maven的配置文件如下:

<plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                    <compilerArguments>
                        <d>bin</d>
                    </compilerArguments>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>copy-dependencies</id>
                        <phase>prepare-package</phase>
                        <goals>
                            <goal>copy-dependencies</goal>
                        </goals>
                        <configuration>
                            <outputDirectory>lib</outputDirectory>
                            <overWriteReleases>false</overWriteReleases>
                            <overWriteSnapshots>false</overWriteSnapshots>
                            <overWriteIfNewer>true</overWriteIfNewer>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <artifactId>maven-assembly-plugin</artifactId>
                <configuration>
                    <descriptors>
                        <descriptor>src/main/assembly/deploy-assembly.xml</descriptor>
                    </descriptors>
                </configuration>
                <executions>
                    <execution>
                        <id>create-artifacts</id>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>

打包的assembly文件src/main/assembly/deploy-assembly.xml如下

<assembly>
    <formats>
        <format>tar.gz</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <dependencySets>
        <dependencySet>
            <!-- include dependencies of our dependencies -->
            <useTransitiveDependencies>false</useTransitiveDependencies>
            <unpack>false</unpack>
            <useProjectArtifact>true</useProjectArtifact>
            <outputDirectory>lib</outputDirectory>
        </dependencySet>
    </dependencySets>
    <fileSets>
        <fileSet>
            <directory>bin</directory>
            <outputDirectory>bin</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>lib</directory>
            <outputDirectory>lib</outputDirectory>
        </fileSet>
        <fileSet>
            <directory>src/main/resources</directory>
            <outputDirectory>src/main/resources</outputDirectory>
        </fileSet>
    </fileSets>
    <files>
        <file>
            <source>testng.xml</source>
            <outputDirectory></outputDirectory>
            <destName>testng.xml</destName>
        </file>
        <file>
            <source>test.bat</source>
            <outputDirectory></outputDirectory>
            <destName>test.bat</destName>
        </file>
    </files>
</assembly>

步骤七,运行TestNG

在不依赖于Eclipse运行TestNG,使用命令 java org.testng.TestNG来运行测试用例,

set projectLocation=%~dp0
cd /D %projectLocation%
set classpath=%projectLocation%\bin;%projectLocation%\lib\*
java org.testng.TestNG %projectLocation%\testng.xml
pause
步骤八,查看test报告

每次运行会自动创建一个以当前时间为目录名的文件夹,里面有test.html,打开此文件即可查看test结果,如下图

使用TestNG实现系统集成测试

步骤九,定时执行测试用例

为了更好的测试系统的稳定性,减少人为的测试干预,我们设为每小时执行一次测试任务,用到了Windows的定时任务,方法如下:

  • 在windows 10或以上搜索Task Scheduler

  • 打开此工具,设置每天每小时执行此脚本,如下图


设置定时计划

设置执行命令


以上是关于使用TestNG实现系统集成测试的主要内容,如果未能解决你的问题,请参考以下文章

Jenkins + TestNG 实现自助式自动化测试平台

TestNG依赖测试

Eclipse集成testng插件(离线安装方式)

Jenkins如何集成运行testng.xml文件的解决方案

JUnit VS TestNG

java+Selenium+TestNg搭建自动化测试架构实现代码和数据的分离