• 1
  • 3
分享

引言

谈到性能测试,部分公司连专门用于性能测试的环境都没有,更别提性能测试框架/平台了。下面,笔者就“基于Jmeter的性能测试框架搭建”这个话题,谈谈自己的一些想法。

工具

  • Jmeter
  • Influxdb
  • Grafana
  • Telegraf
  • Jenkins
  • Ant
  • Gitlab

理念

  • 测试人员只需专注脚本编写及性能结果分析。脚本提交Gitlab后自动触发构建,性能结果实时展现。
  • 性能测试脚本统一管理。

 

实现方法

  • 依赖Jmeter的Backend Listener监听器及Telegraf,采集tps,响应时间,cpu,内存等信息至Influxdb时序数据库,然后再通过Grafana展现性能结果。
  • 依赖Jenkins的webhook插件监听push事件,即push脚本至gitlab则触发Ant构建。

一、脚本上传小工具开发



为了简便测试人员操作,特开发此压测小工具,实现功能如下:

  • 上传脚本前,初始化本地git仓库。
  • 克隆git仓库。
  • 根据上传的脚本修改build.xml文件。
  • push脚本和build.xml文件。

使用JGit访问Gitlab,dom4j处理xml文件。pom.xml配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<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.0</modelVersion>

    <groupId>com.tool</groupId>
    <artifactId>performanceTestTool</artifactId>
    <version>1.0-SNAPSHOT</version>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <configuration>
                    <source>6</source>
                    <target>6</target>
                </configuration>
            </plugin>
        </plugins>
    </build>


    <repositories>
        <repository>
            <id>jgit-repository</id>
            <url>https://repo.eclipse.org/content/groups/releases/</url>
        </repository>
    </repositories>

    <!-- Core Library -->
    <dependencies>
        <dependency>
            <groupId>org.eclipse.jgit</groupId>
            <artifactId>org.eclipse.jgit</artifactId>
            <version>4.11.0.201803080745-r</version>
        </dependency>

        <!-- Smart HTTP Servlet -->
        <dependency>
            <groupId>org.eclipse.jgit</groupId>
            <artifactId>org.eclipse.jgit.http.server</artifactId>
            <version>4.11.0.201803080745-r</version>
        </dependency>

        <!-- AWT UI Helpers -->
        <dependency>
            <groupId>org.eclipse.jgit</groupId>
            <artifactId>org.eclipse.jgit.ui</artifactId>
            <version>4.11.0.201803080745-r</version>
        </dependency>

        <!-- JUnit Test Support -->
        <dependency>
            <groupId>org.eclipse.jgit</groupId>
            <artifactId>org.eclipse.jgit.junit</artifactId>
            <version>4.11.0.201803080745-r</version>
        </dependency>

        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
    </dependencies>

</project>

clone项目至本地仓库:

    public static void cloneProject() throws Exception {

        //每次clone前先初始化
        Util.deletefile(localProject);

        File file = new File(localProject);
        try {
            //克隆代码库命令
            CloneCommand cloneCommand = Git.cloneRepository();
            cloneCommand.setURI(remoteRepoURI) //设置远程URI
                    .setBranch("master") //设置clone下来的分支
                    .setDirectory(file) //设置下载存放路径
                    .setCredentialsProvider(usernamePasswordCredentialsProvider)
                    .call();
        } catch (GitAPIException e) {
            e.printStackTrace();
        }
    }

pull操作:

    public static void pullFiles() throws IOException, GitAPIException {

        //git仓库地址
        Git git = new Git(new FileRepository(localProject+"/.git"));
        git.pull().setRemoteBranchName("master").
                setCredentialsProvider(usernamePasswordCredentialsProvider).call();
    }

push操作:

    public static void pushFiles(String filePath,String commitMess) throws IOException, GitAPIException {

        File fileFrom = new File(filePath);
        File fileTemp = new File(localProject);
        File fileTo = new File(fileTemp.getAbsolutePath()+"/"+fileFrom.getName());
        fileTo.createNewFile();

        Util.copyFiles(fileFrom,fileTo);  //拷贝脚本文件至git本地仓库

        Repository rep = new FileRepository(localProject+"\\.git");
        Git git1 = new Git(rep);
        git1.add().addFilepattern(fileFrom.getName()).call();  //此处必须使用本地仓库中需推送的文件名
        git1.add().addFilepattern("build.xml").call();         //push修改后的build文件
        //提交
        git1.commit().setMessage(commitMess).call();
        git1.push().setCredentialsProvider(usernamePasswordCredentialsProvider).call();
    }

build.xml文件配置:

<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<project basedir="." default="run" name="Ant">
    <tstamp>
        <format pattern="yyyyMMddhhmm" property="time"/>
    </tstamp>
    <!-- jmeter路径-->  
    <property name="jmeter.home" value="D:\tools\PerformanceTesting\Jmeter_influxdb_grafana\apache-jmeter-3.1"/>
    <!-- jmeter jtl测试报告生成路径--> 
    <property name="jmeter.result.jtl.dir" value="D:\tools\PerformanceTesting\Jmeter_influxdb_grafana\apache-jmeter-3.1\TestCase\report\jtl"/>
    <!-- jmeter html测试报告生成路径-->
    <property name="jmeter.result.html.dir" value="D:\tools\PerformanceTesting\Jmeter_influxdb_grafana\apache-jmeter-3.1\TestCase\report\html"/>
    <!-- 参数化-->  
    <property name="ReportName" value="TestReport"/>
    <property name="jmeter.result.jtlName" value="${jmeter.result.jtl.dir}/${ReportName}${time}.jtl"/>
    <property name="jmeter.result.htmlName" value="${jmeter.result.html.dir}/${ReportName}${time}.html"/>
    
    <target name="run">
        <antcall target="test"/>
        <!--性能脚本构建时,生成报告时间太长,注释掉 -->
        <!-- antcall target="report"/ -->
    </target>
    
    <target name="test">
        <taskdef classname="org.programmerplanet.ant.taskdefs.jmeter.JMeterTask" name="jmeter"/>
        <jmeter jmeterhome="${jmeter.home}" resultlog="${jmeter.result.jtlName}">
             <!-- 构建路径,与jenkins上工作空间配置保持一致 -->
            <testplans dir="D:\tools\PerformanceTesting\Jmeter_influxdb_grafana\apache-jmeter-3.1\TestCase\jenkins_jobworkspace" includes="测试.jmx"/>
            <property name="jmeter.save.saveservice.output_format" value="xml"/>

        </jmeter>
    </target>
        
    <target name="report">
        <xslt in="${jmeter.result.jtlName}" out="${jmeter.result.htmlName}" style="${jmeter.home}/extras/jmeter.results.shanhe.me.xsl"/>
                <!-- 测试报告--> 
        <copy todir="${jmeter.result.html.dir}">
            <fileset dir="${jmeter.home}/extras">
                <include name="collapse.png"/>
                <include name="expand.png"/>
            </fileset>
        </copy>
    </target>
</project>

通过分析上面的build.xml文件,发现构建脚本由includes的值来定义,如果值为“*.jmx”,则会构建dir目录下所有的jmx文件。由于我们只需构建上传的脚本,那有必要修改build文件,使includes的值等于上传的脚本名称。

<testplans dir="D:\tools\PerformanceTesting\Jmeter_influxdb_grafana\apache-jmeter-3.1\TestCase\jenkins_jobworkspace" includes="测试.jmx"/>

修改build文件的includes值:

    public static void modifyBuild(String filePath,String modifyName) throws ParserConfigurationException, IOException, SAXException {

        DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

        DocumentBuilder db = dbf.newDocumentBuilder();
        Document doc = db.parse(new File(filePath)); // 读取xml文件

        NodeList targetList = doc.getElementsByTagName("testplans");  //获取testplans节点

        for (int i = 0; i < targetList.getLength(); i++) {
            Node case_node = targetList.item(i); // 第一个caseNo节点

            Element elem0 = (Element) case_node; // caseNo节点对象
            String target_name = elem0.getAttribute("includes");
            System.out.println("修改前includes = " + target_name); // 节点属性

            elem0.setAttribute("includes",modifyName);
            String target_name1 = elem0.getAttribute("includes");
            System.out.println("修改后includes = " + target_name1); // 节点属性
        }
        saveXml(filePath, doc);
    }

至此,第一阶段的工作已完成。当然,你也可以通过Git bash来push脚本触发构建,但是你得另外想办法来控制脚本的构建,因为Ant是根据build.xml文件来指定构建哪些脚本的。

二、配置Jenkins,Gitlab

  • 安装jenkins插件。 Ant Plugin,Git plugin,GitLab Plugin,Gitlab Hook Plugin,可以在线安装,也可以下载本地安装,下载地址
  • jenkins-系统配置-全局工具配置。 配置jdk,git,ant。  
  • jenkins-项目-配置。 自定义空间与build.xml设置的构建路径保持一致,jenkins构建时,会把git仓库pull到该路径下。
<testplans dir="D:\tools\PerformanceTesting\Jmeter_influxdb_grafana\apache-jmeter-3.1\TestCase\jenkins_jobworkspace" includes="测试.jmx"/>



注意下图的Targets需同build.xml文件一致。

    <target name="run">
        <antcall target="test"/>
        <!--性能脚本构建时,生成报告时间太长,注释掉 -->
        <!-- antcall target="report"/ -->
    </target>


由于依赖webhook来监听push事件触发构建,拷贝下图的URL,并在“高级”选项中生成“Secret token”,后续在gitlab添加webhook。



  • gitlab-webhook配置。 由于只需监听push事件,所有下图只勾选了Push events“”。添加webhook后,点击“Test”进行测试,如果返回200/201,则表明webhook配置成功。

如果不想使用Secret token配置webhook,也可按以下方式来配置: 打开jenkins的“设置”页面,找到API Token,然后在gitlab上添加webhook url即可,结构如下图2所示(UserId:APIToken@jenkins构建器url)。

三、配置Influxdb,Grafana,Telegraf

Influxdb+Grafana+Telegraf在笔者的另一篇文章<Jmeter排忧解难—性能测试监控>有提及,百度也大把文章,此处不再详述。

四、编写测试脚本

使用jmeter编写一个简单的测试脚本来进行测试,主要依赖Backend Listener监听器来集成influxdb。



五、性能结果分析

运行“一、脚本上传小工具开发”提及的压测小工具,就可以对性能结果做实时监控了。最终实现效果图如下所示。


六、构建日志

登录jenkins,可以查看详细的构建日志。

七、扩展


《基于Jmeter的性能测试框架搭建》改进一

《基于Jmeter的性能测试框架搭建》改进二

  • 【留下美好印记】
    赞赏支持
登录 后发表评论
+ 关注

热门文章

    最新讲堂

      • 推荐阅读
      • 换一换
          •   本文的主要内容是介绍如何在Linux CentOS 服务器上面搭建Jmeter的压测环境整个详细的流程,来满足我们日常工作中对于压力测试环境搭建、压力测试执行过程的需求。  一、首先我们要准备四个东西,在搭建环境的时候需要使用到  1、Xshell、puTTy等终端连接工具(本文教程使用Xshell)  Xshell用于连接Linux CentOS 服务器,为我们提供操作服务器的可视化界面,如何连接服务器本文不做赘述,如果有需要请自行联网搜索,网上教程很多。连接成功如下:  2、Jmeter压缩安装包  Jmeter的压缩包需要自己去Jmeter的官网进行下载,由于是在centos环境下,...
            1 1 3755
            分享
          • 印象中,测试流程制度这块,我们每年都会更新,当然啦,还是hr追的紧啊,主要目的说是为了保障线上质量。浅浅分享一下吧,觉得实用可以直接抱走。今年我们主要抓的部分分为两个,一个是计划达成率,一个是线上质量。按照实际完成的情况进行加分或者扣分。一、【计划达成率】按照测试计划及测试用例进行测试,符合相关项目规范,100%完成开发计划。因个人原因,每延迟一天,扣10分,项目整体提前一天及以上,加10分。(项目具体日期按照项目评估时间进行)二、【上线后质量】产品/功能上线后的经分析是测试遗漏导致的bug,进行扣分。若是P1级别的bug,1个扣10分,若是P2级别bug,1个扣5分,若是P3级别bug,扣1...
            1 0 1718
            分享
          •   IEEE Spectrum 出炉了 2022 年度最受欢迎编程语言排名。该排名最初由数据记者 Nick Diakopoulos 于 2013 年创建,今年是第九届。当前版本由 IEEE Spectrum 高级编辑 Stephen Cass 维护,并得到 Prachi Patel 和 Michael Novakovic 的开发支持。  作为业内比较权威的交互语言排行榜,本次排名结合了包括谷歌搜索、推特、Stack Overflow、Reddit、IEEE、GitHub 等 8 个来源的 9 项指标,共上榜了 57 种语言。关于指标,例如在 Stack Overflow 中,程序员可以在其中询...
            0 0 944
            分享
          •   工作以来,大大小小参与的项目也有十几个了,涵盖财务类、保险类、OA办公类软件,从测试流程上看,基本也都大同小异,这里将常见的测试流程做一些梳理,供刚入行的朋友学习参考,也欢迎大家完善补充。  一、需求答疑评审  参与人员:  产品、开发、测试、需求提出人、其它相关人员。  主要内容:  对需求文档进行评审,对于有疑问或者有错误的地方,进行讨论沟通,来保证对需求理解的准确性和一致性。需求文档中最好有业务流程图,能够较好的帮助相关人员快速的了解业务需求。  目标达成:  通过此次会议了解到各模块对应开发人员,以此来确定测试时间  二、罗列测试点  主要内容:  需求评审通过后,测试根据定版的需...
            0 0 921
            分享
          •   Selenium是一个用于自动化Web浏览器的Python库。它提供了一组强大的工具和API,使开发者能够以编程方式控制浏览器的行为,模拟用户与网页的交互。  Selenium可以用于各种Web自动化任务,包括网页测试、数据采集、UI自动化等。它支持主流的Web浏览器,如Chrome、Firefox、Safari等,并提供了丰富的功能,例如:  页面导航:Selenium可以模拟用户在浏览器中输入URL或点击链接来导航到不同的网页。  元素定位和操作:开发者可以使用Selenium定位页面上的元素,例如文本框、按钮、下拉菜单等,并进行点击、输入文本、提交表单等操作。  页面截图:Selen...
            0 0 1236
            分享
      • 51testing软件测试圈微信